-
-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Implement searching for the Table page #158
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,13 +807,15 @@ 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"; | ||
this.Text = "Less MSIérables"; | ||
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); } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like we had to make the SearchPanel smart enough to know that his grid could change. This function is already checking for an empty searchPanel and creating it once if needed. I wonder if it wouldn't be cleaner to just do this in the cancel action/callback here:
Then There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you like me to keep it as events in this case, as to minimize the amount of changes needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And some events still need to be de-registered, for example: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No concern about these callback events. Regarding need to unsubscribe: I remember when I wrote this thinking that calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, sadly it is very hard to reliably test UI. The dispose would only add value in an instance like this if we add an OnDispose event handler, and actively unsubscribe in that. Another thing that could be an option is to create one search dialog per tab. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think "remembering" the search between tabs is going to be more confusing to the user. Better to clear it probably (the app might remember, but the user won't :)). Again, as for dispose or not, you decide. Just please test and make sure it works good and I'll trust your judgement. |
||
); | ||
} | ||
} | ||
|
||
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(); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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<MsiFileItemView> fileDataSource; | ||
private IList<object[]> tableViewDataSource; | ||
activescott marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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 | ||
/// </summary> | ||
/// <param name="searchTerm">Search term or <see cref="String.Empty"/> to cancel the search.</param> | ||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets remove the |
||
{ | ||
if (this.tableViewDataSource != null) | ||
{ | ||
IList<object[]> 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); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be
if (obj != null && obj.ToString().Contains(needle, comparisonType))
. Without it I was encountering exceptions.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@activescott do you happen to have an example MSI to test this on?