From 45b9d7d4d6a84ef5366352aa747f7f397319d112 Mon Sep 17 00:00:00 2001 From: xantari Date: Sun, 10 Jan 2021 11:26:59 -0600 Subject: [PATCH] speed tweeks working --- .../DatabaseBrowserForm.Designer.cs | 157 ++++++++-------- PinCab.Configurator/DatabaseBrowserForm.cs | 172 ++++++++++++++---- PinCab.Utils/Extensions/ListExtensions.cs | 2 +- PinCab.Utils/Extensions/WinformsExtensions.cs | 91 +++++++++ PinCab.Utils/PinCab.Utils.csproj | 1 + PinCab.Utils/Utils/DatabaseManager.cs | 99 ++++++++-- PinCab.Utils/Utils/WinApi.cs | 16 ++ 7 files changed, 410 insertions(+), 128 deletions(-) create mode 100644 PinCab.Utils/Utils/WinApi.cs diff --git a/PinCab.Configurator/DatabaseBrowserForm.Designer.cs b/PinCab.Configurator/DatabaseBrowserForm.Designer.cs index b43732a..429fd2a 100644 --- a/PinCab.Configurator/DatabaseBrowserForm.Designer.cs +++ b/PinCab.Configurator/DatabaseBrowserForm.Designer.cs @@ -29,7 +29,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -53,6 +53,14 @@ private void InitializeComponent() this.lblRomSearch = new System.Windows.Forms.Label(); this.txtSearch = new System.Windows.Forms.TextBox(); this.dataGridViewEntryList = new System.Windows.Forms.DataGridView(); + this.titleDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.DatabaseTagsString = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.Url = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.IpdbId = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.Version = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.LastUpdated = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.TypeString = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.DatabaseTypeString = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.contextMenuStripGridActions = new System.Windows.Forms.ContextMenuStrip(this.components); this.IpdbInfoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.goToUrlToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -64,14 +72,6 @@ private void InitializeComponent() this.toolStripStatusLabelSpacer = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripProgressBar = new System.Windows.Forms.ToolStripProgressBar(); this.statusStripBottom = new System.Windows.Forms.StatusStrip(); - this.titleDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.DatabaseTagsString = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.Url = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.IpdbId = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.Version = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.LastUpdated = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.TypeString = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.DatabaseTypeString = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.menuStrip1.SuspendLayout(); this.panelFilterCriteria.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.dataGridViewEntryList)).BeginInit(); @@ -321,8 +321,77 @@ private void InitializeComponent() this.dataGridViewEntryList.ReadOnly = true; this.dataGridViewEntryList.Size = new System.Drawing.Size(1049, 288); this.dataGridViewEntryList.TabIndex = 2; + this.dataGridViewEntryList.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridViewEntryList_CellDoubleClick); this.dataGridViewEntryList.DataBindingComplete += new System.Windows.Forms.DataGridViewBindingCompleteEventHandler(this.dataGridViewEntryList_DataBindingComplete); // + // titleDataGridViewTextBoxColumn + // + this.titleDataGridViewTextBoxColumn.DataPropertyName = "Title"; + this.titleDataGridViewTextBoxColumn.HeaderText = "Title"; + this.titleDataGridViewTextBoxColumn.Name = "titleDataGridViewTextBoxColumn"; + this.titleDataGridViewTextBoxColumn.ReadOnly = true; + this.titleDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this.titleDataGridViewTextBoxColumn.Width = 52; + // + // DatabaseTagsString + // + this.DatabaseTagsString.DataPropertyName = "DatabaseTagsString"; + dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.DatabaseTagsString.DefaultCellStyle = dataGridViewCellStyle2; + this.DatabaseTagsString.HeaderText = "Tags"; + this.DatabaseTagsString.Name = "DatabaseTagsString"; + this.DatabaseTagsString.ReadOnly = true; + this.DatabaseTagsString.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.DatabaseTagsString.Width = 37; + // + // Url + // + this.Url.DataPropertyName = "Url"; + this.Url.HeaderText = "Url"; + this.Url.Name = "Url"; + this.Url.ReadOnly = true; + this.Url.Width = 45; + // + // IpdbId + // + this.IpdbId.DataPropertyName = "IpdbId"; + this.IpdbId.HeaderText = "Ipdb"; + this.IpdbId.Name = "IpdbId"; + this.IpdbId.ReadOnly = true; + this.IpdbId.Width = 53; + // + // Version + // + this.Version.DataPropertyName = "Version"; + this.Version.HeaderText = "Version"; + this.Version.Name = "Version"; + this.Version.ReadOnly = true; + this.Version.Width = 67; + // + // LastUpdated + // + this.LastUpdated.DataPropertyName = "LastUpdated"; + this.LastUpdated.HeaderText = "Updated"; + this.LastUpdated.Name = "LastUpdated"; + this.LastUpdated.ReadOnly = true; + this.LastUpdated.Width = 73; + // + // TypeString + // + this.TypeString.DataPropertyName = "TypeString"; + this.TypeString.HeaderText = "Type"; + this.TypeString.Name = "TypeString"; + this.TypeString.ReadOnly = true; + this.TypeString.Width = 56; + // + // DatabaseTypeString + // + this.DatabaseTypeString.DataPropertyName = "DatabaseTypeString"; + this.DatabaseTypeString.HeaderText = "DB"; + this.DatabaseTypeString.Name = "DatabaseTypeString"; + this.DatabaseTypeString.ReadOnly = true; + this.DatabaseTypeString.Width = 47; + // // contextMenuStripGridActions // this.contextMenuStripGridActions.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -337,12 +406,14 @@ private void InitializeComponent() this.IpdbInfoToolStripMenuItem.Name = "IpdbInfoToolStripMenuItem"; this.IpdbInfoToolStripMenuItem.Size = new System.Drawing.Size(127, 22); this.IpdbInfoToolStripMenuItem.Text = "IPDB Info"; + this.IpdbInfoToolStripMenuItem.Click += new System.EventHandler(this.IpdbInfoToolStripMenuItem_Click); // // goToUrlToolStripMenuItem // this.goToUrlToolStripMenuItem.Name = "goToUrlToolStripMenuItem"; this.goToUrlToolStripMenuItem.Size = new System.Drawing.Size(127, 22); this.goToUrlToolStripMenuItem.Text = "Go to URL"; + this.goToUrlToolStripMenuItem.Click += new System.EventHandler(this.goToUrlToolStripMenuItem_Click); // // vpinDatabaseSettingBindingSource // @@ -413,74 +484,6 @@ private void InitializeComponent() this.statusStripBottom.TabIndex = 6; this.statusStripBottom.Text = "statusStrip1"; // - // titleDataGridViewTextBoxColumn - // - this.titleDataGridViewTextBoxColumn.DataPropertyName = "Title"; - this.titleDataGridViewTextBoxColumn.HeaderText = "Title"; - this.titleDataGridViewTextBoxColumn.Name = "titleDataGridViewTextBoxColumn"; - this.titleDataGridViewTextBoxColumn.ReadOnly = true; - this.titleDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this.titleDataGridViewTextBoxColumn.Width = 52; - // - // DatabaseTagsString - // - this.DatabaseTagsString.DataPropertyName = "DatabaseTagsString"; - dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True; - this.DatabaseTagsString.DefaultCellStyle = dataGridViewCellStyle1; - this.DatabaseTagsString.HeaderText = "Tags"; - this.DatabaseTagsString.Name = "DatabaseTagsString"; - this.DatabaseTagsString.ReadOnly = true; - this.DatabaseTagsString.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.DatabaseTagsString.Width = 37; - // - // Url - // - this.Url.DataPropertyName = "Url"; - this.Url.HeaderText = "Url"; - this.Url.Name = "Url"; - this.Url.ReadOnly = true; - this.Url.Width = 45; - // - // IpdbId - // - this.IpdbId.DataPropertyName = "IpdbId"; - this.IpdbId.HeaderText = "Ipdb"; - this.IpdbId.Name = "IpdbId"; - this.IpdbId.ReadOnly = true; - this.IpdbId.Width = 53; - // - // Version - // - this.Version.DataPropertyName = "Version"; - this.Version.HeaderText = "Version"; - this.Version.Name = "Version"; - this.Version.ReadOnly = true; - this.Version.Width = 67; - // - // LastUpdated - // - this.LastUpdated.DataPropertyName = "LastUpdated"; - this.LastUpdated.HeaderText = "Updated"; - this.LastUpdated.Name = "LastUpdated"; - this.LastUpdated.ReadOnly = true; - this.LastUpdated.Width = 73; - // - // TypeString - // - this.TypeString.DataPropertyName = "TypeString"; - this.TypeString.HeaderText = "Type"; - this.TypeString.Name = "TypeString"; - this.TypeString.ReadOnly = true; - this.TypeString.Width = 56; - // - // DatabaseTypeString - // - this.DatabaseTypeString.DataPropertyName = "DatabaseTypeString"; - this.DatabaseTypeString.HeaderText = "DB"; - this.DatabaseTypeString.Name = "DatabaseTypeString"; - this.DatabaseTypeString.ReadOnly = true; - this.DatabaseTypeString.Width = 47; - // // DatabaseBrowserForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/PinCab.Configurator/DatabaseBrowserForm.cs b/PinCab.Configurator/DatabaseBrowserForm.cs index a83246d..48ba9dc 100644 --- a/PinCab.Configurator/DatabaseBrowserForm.cs +++ b/PinCab.Configurator/DatabaseBrowserForm.cs @@ -12,9 +12,11 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; +using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; @@ -32,6 +34,11 @@ public DatabaseBrowserForm() _dbManager = new DatabaseManager(backgroundWorkerProgressBar.ReportProgress); + if (!SystemInformation.TerminalServerSession) + DoubleBuffered = true; + else + DoubleBuffered = false; + ConfigureFilters(); ConfigureGrid(); LoadDatabaseGrid(); @@ -80,6 +87,22 @@ private void ConfigureGrid() column.Resizable = DataGridViewTriState.True; } dataGridViewEntryList.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells; + //Speed tweak testing + //dataGridViewEntryList.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None; + //dataGridViewEntryList.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None; + //dataGridViewEntryList.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing; + //dataGridViewEntryList.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + //dataGridViewEntryList.RowHeadersVisible = false; + //// Double buffering can make DGV slow in remote desktop + //if (!System.Windows.Forms.SystemInformation.TerminalServerSession) + //{ + // typeof(DataGridView).InvokeMember( + // "DoubleBuffered", + // BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, + // null, + // dataGridViewEntryList, + // new object[] { true }); + //} } private void exitToolStripMenuItem_Click(object sender, EventArgs e) @@ -162,10 +185,10 @@ private int GetActiveRowIndex() return rowIndex; } - private DatabaseBrowserEntry GetActiveRowRom() + private DatabaseBrowserEntry GetActiveRowEntry() { - var data = vpinDatabaseSettingBindingSource.DataSource as BindingSource; - return data.Current as DatabaseBrowserEntry; + var data = vpinDatabaseSettingBindingSource.Current as DatabaseBrowserEntry; + return data; } private void backgroundWorkerProgressBar_ProgressChanged(object sender, ProgressChangedEventArgs e) @@ -182,20 +205,36 @@ private void backgroundWorkerProgressBar_RunWorkerCompleted(object sender, RunWo if (result.MessageType == ValidationMessageType.ToolMessage) LogToolValidationResult(result.ToolName, result); } - if (result.FunctionExecuted == DatabaseManagerBackgroundProgressAction.DownloadDatabases.ToString()) - { - //RefreshGrid(); - } - else if (result.FunctionExecuted == DatabaseManagerBackgroundProgressAction.ProcessDatabase.ToString()) - { + //if (result.FunctionExecuted == DatabaseManagerBackgroundProgressAction.DownloadDatabases.ToString()) + //{ + // //RefreshGrid(); + //} + //else if (result.FunctionExecuted == DatabaseManagerBackgroundProgressAction.ProcessDatabase.ToString()) + //{ - } - else if (result.FunctionExecuted == DatabaseManagerBackgroundProgressAction.DownloadAndLoadDatabase.ToString()) + //} + if (result.FunctionExecuted == DatabaseManagerBackgroundProgressAction.DownloadAndLoadDatabase.ToString()) { if (result.Result != null) { + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); var entries = result.Result as List; vpinDatabaseSettingBindingSource.DataSource = entries.ToSortableBindingList(); + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + var msg = $"Grid binding took: {ts.TotalSeconds} seconds"; + Log.Information(msg); + var logResult = new ValidationResult() + { + IsValid = true + }; + logResult.Messages.Add(new ValidationMessage() + { + Level = MessageLevel.Information, + Message = msg + }); + LogToolValidationResult(result.ToolName, logResult); var action = new DatabaseManagerBackgroundAction(); action.Action = DatabaseManagerBackgroundProgressAction.LoadTags; @@ -230,26 +269,26 @@ private void UpdateToolstripStatus() private void backgroundWorkerProgressBar_DoWork(object sender, DoWorkEventArgs e) { var arg = (DatabaseManagerBackgroundAction)e.Argument; - if (arg.Action == DatabaseManagerBackgroundProgressAction.DownloadDatabases) - { - var result = _dbManager.RefreshAllDatabases(); - var toolResult = new ToolResult(result); - toolResult.ToolName = DatabaseManager.ToolName; - toolResult.MessageType = ValidationMessageType.ToolMessage; - toolResult.FunctionExecuted = arg.Action.ToString(); - e.Result = toolResult; - } - else if (arg.Action == DatabaseManagerBackgroundProgressAction.ProcessDatabase) - { - var result = _dbManager.GetAllEntries(); - var toolResult = new ToolResult(); - toolResult.ToolName = DatabaseManager.ToolName; - toolResult.MessageType = ValidationMessageType.ToolMessage; - toolResult.FunctionExecuted = arg.Action.ToString(); - toolResult.Result = result; - e.Result = toolResult; - } - else if (arg.Action == DatabaseManagerBackgroundProgressAction.DownloadAndLoadDatabase) + //if (arg.Action == DatabaseManagerBackgroundProgressAction.DownloadDatabases) + //{ + // var result = _dbManager.RefreshAllDatabases(); + // var toolResult = new ToolResult(result); + // toolResult.ToolName = DatabaseManager.ToolName; + // toolResult.MessageType = ValidationMessageType.ToolMessage; + // toolResult.FunctionExecuted = arg.Action.ToString(); + // e.Result = toolResult; + //} + //else if (arg.Action == DatabaseManagerBackgroundProgressAction.ProcessDatabase) + //{ + // var result = _dbManager.GetAllEntries(); + // var toolResult = new ToolResult(); + // toolResult.ToolName = DatabaseManager.ToolName; + // toolResult.MessageType = ValidationMessageType.ToolMessage; + // toolResult.FunctionExecuted = arg.Action.ToString(); + // toolResult.Result = result; + // e.Result = toolResult; + //} + if (arg.Action == DatabaseManagerBackgroundProgressAction.DownloadAndLoadDatabase) { e.Result = DownloadAndLoadDatabase(); } @@ -261,12 +300,17 @@ private void backgroundWorkerProgressBar_DoWork(object sender, DoWorkEventArgs e private ToolResult DownloadAndLoadDatabase() { + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); var result = _dbManager.RefreshAllDatabases(); List entries = new List(); if (result.IsValid) { _dbManager.LoadAllDatabases(); - entries = _dbManager.GetAllEntries(); + //A true value indicates there was a re-download of one or more databases from the internet + //so we will need to re-create the cached data + var forceReload = (bool)result.Result; + entries = _dbManager.GetAllEntries(forceReload); } var toolResult = new ToolResult(result); toolResult.ToolName = DatabaseManager.ToolName; @@ -279,12 +323,23 @@ private ToolResult DownloadAndLoadDatabase() Level = MessageLevel.Information, Message = "Grid loaded." }); + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Information($"Database Loaded in: {ts.TotalSeconds} seconds"); + toolResult.Messages.Add(new ValidationMessage() + { + Level = MessageLevel.Information, + Message = $"Database Loaded in: {ts.TotalSeconds} seconds" + }); return toolResult; } private ToolResult LoadTags() { - //TODO: Load the tags based off of the current filter + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + //var tagsByCritera = GetEntriesByFilterCriteria(); //vs: _dbManager.Entries (all entries) + //var list = var tags = _dbManager.GetAllTags(_dbManager.Entries).OrderBy(c => c).ToList(); tags.Insert(0, "(Select Tag)"); var toolResult = new ToolResult(); @@ -297,6 +352,14 @@ private ToolResult LoadTags() Level = MessageLevel.Information, Message = "Tags loaded." }); + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Information($"Tags Loaded in: {ts.TotalSeconds} seconds"); + toolResult.Messages.Add(new ValidationMessage() + { + Level = MessageLevel.Information, + Message = $"Tags Loaded in: {ts.TotalSeconds} seconds" + }); return toolResult; } @@ -325,7 +388,7 @@ public void LogToolValidationResult(string command, ValidationResult result) private void helpToolStripMenuItem_Click(object sender, EventArgs e) { - System.Diagnostics.Process.Start("https://github.com/xantari/PinCab.Configurator/wiki/Database-Browser"); + Process.Start("https://github.com/xantari/PinCab.Configurator/wiki/Database-Browser"); } private void refreshDatabaseToolStripMenuItem_Click(object sender, EventArgs e) @@ -337,7 +400,10 @@ private void refreshDatabaseToolStripMenuItem_Click(object sender, EventArgs e) private void dataGridViewEntryList_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) { - dataGridViewEntryList.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); + dataGridViewEntryList.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells); + //dataGridViewEntryList.FastAutoSizeColumns(); + //var colSizes = WinformsExtensions.GetAutoSizeColumnsWidth(dataGridViewEntryList); + //WinformsExtensions.SetAutoSizeColumnsWidth(dataGridViewEntryList, colSizes); } private void cmbDatabase_SelectedIndexChanged(object sender, EventArgs e) @@ -381,5 +447,41 @@ public List GetAllSelectedTags() } return list; } + + private void IpdbInfoToolStripMenuItem_Click(object sender, EventArgs e) + { + var row = GetActiveRowEntry(); + if (row != null) + { + if (row.IpdbId.HasValue) + { + Process.Start($"https://www.ipdb.org/machine.cgi?id={row.IpdbId.Value}"); + } + } + } + + private void goToUrlToolStripMenuItem_Click(object sender, EventArgs e) + { + var row = GetActiveRowEntry(); + if (row != null) + { + if (!string.IsNullOrEmpty(row.Url)) + { + Process.Start(row.Url); + } + } + } + + private void dataGridViewEntryList_CellDoubleClick(object sender, DataGridViewCellEventArgs e) + { + var row = GetActiveRowEntry(); + if (row != null) + { + if (!string.IsNullOrEmpty(row.Url)) + { + Process.Start(row.Url); + } + } + } } } diff --git a/PinCab.Utils/Extensions/ListExtensions.cs b/PinCab.Utils/Extensions/ListExtensions.cs index 69fcad6..b7a7412 100644 --- a/PinCab.Utils/Extensions/ListExtensions.cs +++ b/PinCab.Utils/Extensions/ListExtensions.cs @@ -17,7 +17,7 @@ public static BindingList ToBindingList(this IEnumerable collection) public static SortableBindingList ToSortableBindingList(this IEnumerable collection) { - return new SortableBindingList(collection.ToList()); + return new SortableBindingList(collection); } public static List ReplaceAllInList(this IEnumerable collection, string stringToReplace, string replacement) diff --git a/PinCab.Utils/Extensions/WinformsExtensions.cs b/PinCab.Utils/Extensions/WinformsExtensions.cs index 111c0af..f3f5a26 100644 --- a/PinCab.Utils/Extensions/WinformsExtensions.cs +++ b/PinCab.Utils/Extensions/WinformsExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; @@ -87,5 +88,95 @@ public static void SetNumericUpDown(this NumericUpDown numeric, uint? value) return null; return Convert.ToUInt32(numeric.Value); } + + /// + /// Provides very fast and basic column sizing for large data sets. + /// + //public static void FastAutoSizeColumns(this DataGridView targetGrid) + //{ + // // Cast out a DataTable from the target grid datasource. + // // We need to iterate through all the data in the grid and a DataTable supports enumeration. + // var gridTable = (BindingSource)targetGrid.DataSource; + + // // Create a graphics object from the target grid. Used for measuring text size. + // using (var gfx = targetGrid.CreateGraphics()) + // { + // // Iterate through the columns. + // for (int i = 0; i < targetGrid.Columns.Count; i++) + // { + // // Leverage Linq enumerator to rapidly collect all the rows into a string array, making sure to exclude null values. + // string[] colStringCollection = gridTablee.Where(r => r.Field(i) != null).Select(r => r.Field(i).ToString()).ToArray(); + + // // Sort the string array by string lengths. + // colStringCollection = colStringCollection.OrderBy((x) => x.Length).ToArray(); + + // // Get the last and longest string in the array. + // string longestColString = colStringCollection.Last(); + + // // Use the graphics object to measure the string size. + // var colWidth = gfx.MeasureString(longestColString, targetGrid.Font); + + // // If the calculated width is larger than the column header width, set the new column width. + // if (colWidth.Width > targetGrid.Columns[i].HeaderCell.Size.Width) + // { + // targetGrid.Columns[i].Width = (int)colWidth.Width; + // } + // else // Otherwise, set the column width to the header width. + // { + // targetGrid.Columns[i].Width = targetGrid.Columns[i].HeaderCell.Size.Width; + // } + // } + // } + //} + + public static int[] GetAutoSizeColumnsWidth(DataGridView grid) + { + var src = ((IEnumerable)grid.DataSource) + .Cast() + .Select(x => x.GetType() + .GetProperties() + .Select(p => p.GetValue(x, null)?.ToString() ?? string.Empty) + .ToArray() + ); + + int[] widths = new int[grid.Columns.Count]; + if (src.Count() == 0) + return widths; + // Iterate through the columns. + for (int i = 0; i < grid.Columns.Count; i++) + { + // Leverage Linq enumerator to rapidly collect all the rows into a string array, making sure to exclude null values. + string[] colStringCollection = src.Where(r => r[i] != null).Select(r => r[i].ToString()).ToArray(); + + // Sort the string array by string lengths. + colStringCollection = colStringCollection.OrderBy((x) => x.Length).ToArray(); + + // Get the last and longest string in the array. + string longestColString = colStringCollection.Last(); + + // Use the graphics object to measure the string size. + var colWidth = TextRenderer.MeasureText(longestColString, grid.Font); + + // If the calculated width is larger than the column header width, set the new column width. + if (colWidth.Width > grid.Columns[i].HeaderCell.Size.Width) + { + widths[i] = (int)colWidth.Width; + } + else // Otherwise, set the column width to the header width. + { + widths[i] = grid.Columns[i].HeaderCell.Size.Width; + } + } + + return widths; + } + + public static void SetAutoSizeColumnsWidth(DataGridView grid, int[] widths) + { + for (int i = 0; i < grid.Columns.Count; i++) + { + grid.Columns[i].Width = widths[i]; + } + } } } diff --git a/PinCab.Utils/PinCab.Utils.csproj b/PinCab.Utils/PinCab.Utils.csproj index 7bdcd54..97c5502 100644 --- a/PinCab.Utils/PinCab.Utils.csproj +++ b/PinCab.Utils/PinCab.Utils.csproj @@ -148,6 +148,7 @@ + diff --git a/PinCab.Utils/Utils/DatabaseManager.cs b/PinCab.Utils/Utils/DatabaseManager.cs index 414ba3b..7c42d5e 100644 --- a/PinCab.Utils/Utils/DatabaseManager.cs +++ b/PinCab.Utils/Utils/DatabaseManager.cs @@ -41,6 +41,8 @@ public class DatabaseManager private string vpDatabasePath = ApplicationHelpers.GetApplicationFolder() + "\\Databases\\vpinballdatabase.json"; private string vpuDatabasePath = ApplicationHelpers.GetApplicationFolder() + "\\Databases\\vpuniversedatabase.json"; private string ipdbDatabasePath = ApplicationHelpers.GetApplicationFolder() + "\\Databases\\ipdbdatabase.json"; + private string preprocessedDatabasePath = ApplicationHelpers.GetApplicationFolder() + "\\Databases\\preprocesseddatabase.json"; + private string tagDatabasePath = ApplicationHelpers.GetApplicationFolder() + "\\Databases\\tagdatabase.json"; private ReportProgressDelegate _reportProgress; @@ -121,14 +123,25 @@ public ToolResult RefreshAllDatabases() _reportProgress?.Invoke(80); var ipdbResult = DownloadDatabase(DatabaseType.IPDB); _reportProgress?.Invoke(100); + var result = new ToolResult(ToolName); result.Messages.AddRange(vpfResult?.Messages); result.Messages.AddRange(vpuResult?.Messages); result.Messages.AddRange(vpsResult?.Messages); result.Messages.AddRange(vpResult?.Messages); result.Messages.AddRange(ipdbResult?.Messages); - _settings.LastDatabaseRefreshTimeUtc = DateTime.UtcNow; - _settingManager.SaveSettings(_settings); + + if (((bool)vpfResult.Result) || ((bool)vpuResult.Result) || ((bool)vpsResult.Result) + || ((bool)vpResult.Result) || ((bool)ipdbResult.Result)) + { + _settings.LastDatabaseRefreshTimeUtc = DateTime.UtcNow; //Only bump the date if we re-downloaded something + result.Result = true; + _settingManager.SaveSettings(_settings); + } + else + { + result.Result = false; //We didn't re-download anything + } result.Messages.Add(new ValidationMessage("Database refresh completed.", MessageLevel.Information)); return result; } @@ -164,12 +177,14 @@ public ToolResult DownloadDatabase(DatabaseType type) DownloadDatabase(type, _settings.IPDBDatabaseUrl, ipdbDatabasePath); result.Messages.Add(new ValidationMessage($"Downloaded {_settings.IPDBDatabaseUrl} to {ipdbDatabasePath}", MessageLevel.Information)); } + result.Result = true; //Inidicate we downloaded something } else { var nextRefreshTime = _settings.LastDatabaseRefreshTimeUtc.AddMinutes(_settings.DatabaseUpdateRecheckMinutes); result.Messages.Add(new ValidationMessage($"Not at recheck minutes threshold. Next Refresh: {nextRefreshTime}. Database: {type}", MessageLevel.Information)); Log.Information("{toolname}: Not at recheck minutes threshold. Next Refresh: {date}.", ToolName, nextRefreshTime); + result.Result = false; //Inidicate we did NOT downloaded something } return result; } @@ -208,19 +223,37 @@ public void LoadAllDatabases() } } - public List GetAllEntries() + public List GetAllEntries(bool forceReload) { var entries = new List(); - _reportProgress?.Invoke(10); - entries.AddRange(GetEntrysByDatabase(DatabaseType.VPForums)); - _reportProgress?.Invoke(30); - entries.AddRange(GetEntrysByDatabase(DatabaseType.VPUniverse)); - _reportProgress?.Invoke(50); - entries.AddRange(GetEntrysByDatabase(DatabaseType.VPSSpreadsheet)); - _reportProgress?.Invoke(70); - entries.AddRange(GetEntrysByDatabase(DatabaseType.VPinball)); - _reportProgress?.Invoke(100); - Entries = entries; + //Ensure a local cached copy exists, otherwise force a reload + if (!File.Exists(preprocessedDatabasePath)) + forceReload = true; + + if (forceReload) + { + _reportProgress?.Invoke(10); + entries.AddRange(GetEntrysByDatabase(DatabaseType.VPForums, forceReload)); + _reportProgress?.Invoke(30); + entries.AddRange(GetEntrysByDatabase(DatabaseType.VPUniverse, forceReload)); + _reportProgress?.Invoke(50); + entries.AddRange(GetEntrysByDatabase(DatabaseType.VPSSpreadsheet, forceReload)); + _reportProgress?.Invoke(70); + entries.AddRange(GetEntrysByDatabase(DatabaseType.VPinball, forceReload)); + _reportProgress?.Invoke(100); + Entries = entries; + //Write the preprocessed database so next load is faster + SaveDatabaseCache(entries, preprocessedDatabasePath); + } + else + { + _reportProgress?.Invoke(10); + entries = JsonConvert.DeserializeObject>(File.ReadAllText(preprocessedDatabasePath)); + Entries = entries; + Log.Information("{toolname}: Loaded preprocessed database.", ToolName, preprocessedDatabasePath); + _reportProgress?.Invoke(100); + } + return entries; } @@ -263,10 +296,11 @@ public List GetDatabaseVersionMessages() return entries; } - public List GetEntrysByDatabase(DatabaseType type) + public List GetEntrysByDatabase(DatabaseType type, bool forceReload) { List entries = new List(); - if (IsValid(type)) + + if (IsValid(type) && forceReload) { if (type == DatabaseType.VPForums) { @@ -301,8 +335,23 @@ public List GetEntrysByDatabase(DatabaseType type) return entries; } } + return entries; } + //We return the preprocessed database if it exists and we haven't reached a condition where we need to refresh the + //database (reached refresh timeframe or the preprocessed database doesn't exist yet) + else if (IsValid(type) && !forceReload) + { + var loadedEntries = JsonConvert.DeserializeObject>(File.ReadAllText(preprocessedDatabasePath)); + if (type == DatabaseType.VPForums) + return loadedEntries.Where(p => p.DatabaseType == DatabaseType.VPForums).ToList(); + else if (type == DatabaseType.VPinball) + return loadedEntries.Where(p => p.DatabaseType == DatabaseType.VPinball).ToList(); + else if (type == DatabaseType.VPSSpreadsheet) + return loadedEntries.Where(p => p.DatabaseType == DatabaseType.VPSSpreadsheet).ToList(); + else if (type == DatabaseType.VPUniverse) + return loadedEntries.Where(p => p.DatabaseType == DatabaseType.VPUniverse).ToList(); + } return null; } @@ -970,5 +1019,25 @@ private List GetTagsByIpdbNumber(int ipdbId) } return list; } + + public void SaveDatabaseCache(T database, string fileAndPathToDatabase) + { + Log.Warning("{tool}: Preprocessed database cache saved to {path}", ToolName, fileAndPathToDatabase); + using (StreamWriter sw = new StreamWriter(fileAndPathToDatabase, false)) + using (JsonWriter writer = new JsonTextWriter(sw)) + { + GetJsonSerilizerSettings().Serialize(writer, database); + } + } + + private JsonSerializer GetJsonSerilizerSettings() + { + JsonSerializer serializer = new JsonSerializer(); + serializer.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); + serializer.NullValueHandling = NullValueHandling.Ignore; + //serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + serializer.Formatting = Formatting.Indented; + return serializer; + } } } diff --git a/PinCab.Utils/Utils/WinApi.cs b/PinCab.Utils/Utils/WinApi.cs new file mode 100644 index 0000000..b8bf21b --- /dev/null +++ b/PinCab.Utils/Utils/WinApi.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace PinCab.Utils.Utils +{ + public static class WinApi + { + [DllImport("user32.dll")] + public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam); + public const int WM_SETREDRAW = 11; + } +}