From ff0142f0148b57bfca3c361287ae891aa8190827 Mon Sep 17 00:00:00 2001 From: Paul Hebble Date: Wed, 8 Aug 2018 21:13:56 +0000 Subject: [PATCH] Add Install Date column to GUI mod list :100644 100644 461847e9 407319cb M GUI/GUIMod.cs :100644 100644 9dccb6d6 2e538722 M GUI/Main.Designer.cs :100644 100644 f8bd12ec a01f4134 M GUI/MainModList.cs :100644 100644 461847e9 43bd6146 M GUI/GUIMod.cs :100644 100644 9dccb6d6 2e538722 M GUI/Main.Designer.cs :100644 100644 f8bd12ec a01f4134 M GUI/MainModList.cs --- GUI/GUIMod.cs | 153 +++++++++++++++++++--------------------- GUI/Main.Designer.cs | 11 +++ GUI/MainModList.cs | 162 +++++++++++++++++++++++++------------------ 3 files changed, 176 insertions(+), 150 deletions(-) diff --git a/GUI/GUIMod.cs b/GUI/GUIMod.cs index 461847e9ad..ecdd50b6b7 100644 --- a/GUI/GUIMod.cs +++ b/GUI/GUIMod.cs @@ -11,17 +11,14 @@ public sealed class GUIMod { private CkanModule Mod { get; set; } - public string Name - { - get { return Mod.name.Trim(); } - } - + public string Name { get; private set; } public bool IsInstalled { get; private set; } public bool HasUpdate { get; private set; } public bool IsIncompatible { get; private set; } public bool IsAutodetected { get; private set; } public string Authors { get; private set; } public string InstalledVersion { get; private set; } + public DateTime? InstallDate { get; private set; } public string LatestVersion { get; private set; } public string DownloadSize { get; private set; } public bool IsCached { get; private set; } @@ -32,7 +29,6 @@ public string Name public string KSPCompatibility { get; private set; } public string KSPCompatibilityLong { get; private set; } - public string KSPversion { get; private set; } public string Abstract { get; private set; } public string Homepage { get; private set; } public string Identifier { get; private set; } @@ -65,36 +61,82 @@ public string Version get { return IsInstalled ? InstalledVersion : LatestVersion; } } + /// + /// Initialize a GUIMod based on an InstalledModule + /// + /// The installed module to represent + /// CKAN registry object for current game instance + /// Current game version + /// If true, mark this module as incompatible + public GUIMod(InstalledModule instMod, IRegistryQuerier registry, KspVersionCriteria current_ksp_version, bool incompatible = false) + : this(instMod.Module, registry, current_ksp_version, incompatible) + { + IsInstalled = true; + IsInstallChecked = true; + InstallDate = instMod.InstallTime; + InstalledVersion = instMod.Module.version.ToString(); + if (LatestVersion == null || LatestVersion.Equals("-")) + { + LatestVersion = InstalledVersion; + } + } + + /// + /// Initialize a GUIMod based on a CkanModule + /// + /// The module to represent + /// CKAN registry object for current game instance + /// Current game version + /// If true, mark this module as incompatible public GUIMod(CkanModule mod, IRegistryQuerier registry, KspVersionCriteria current_ksp_version, bool incompatible = false) + : this(mod.identifier, registry, current_ksp_version, incompatible) { - IsCKAN = mod is CkanModule; - //Currently anything which could alter these causes a full reload of the modlist - // If this is ever changed these could be moved into the properties - Mod = mod; - IsInstalled = registry.IsInstalled(mod.identifier, false); - IsInstallChecked = IsInstalled; - HasUpdate = registry.HasUpdate(mod.identifier, current_ksp_version); - IsIncompatible = incompatible || !mod.IsCompatibleKSP(current_ksp_version); - IsAutodetected = registry.IsAutodetected(mod.identifier); - Authors = mod.author == null ? "N/A" : String.Join(",", mod.author); - - var installed_version = registry.InstalledVersion(mod.identifier); - ModuleVersion latest_version = null; - var ksp_version = mod.ksp_version; + Mod = mod; + IsCKAN = mod is CkanModule; + + Name = mod.name.Trim(); + Abstract = mod.@abstract.Trim(); + Abbrevation = new string(Name.Split(' ').Where(s => s.Length > 0).Select(s => s[0]).ToArray()); + Authors = mod.author == null ? "N/A" : String.Join(",", mod.author); + HasUpdate = registry.HasUpdate(mod.identifier, current_ksp_version); + DownloadSize = mod.download_size == 0 ? "N/A" : CkanModule.FmtSize(mod.download_size); + IsIncompatible = IsIncompatible || !mod.IsCompatibleKSP(current_ksp_version); + + if (mod.resources != null) + { + Homepage = mod.resources.homepage?.ToString() + ?? mod.resources.spacedock?.ToString() + ?? mod.resources.curse?.ToString() + ?? mod.resources.repository?.ToString() + ?? "N/A"; + } + + UpdateIsCached(); + } + + /// + /// Initialize a GUIMod based on just an identifier + /// + /// The id of the module to represent + /// CKAN registry object for current game instance + /// Current game version + /// If true, mark this module as incompatible + public GUIMod(string identifier, IRegistryQuerier registry, KspVersionCriteria current_ksp_version, bool incompatible = false) + { + Identifier = identifier; + IsIncompatible = incompatible; + IsAutodetected = registry.IsAutodetected(identifier); + + ModuleVersion latest_version = null; try { - var latest_available = registry.LatestAvailable(mod.identifier, current_ksp_version); - if (latest_available != null) - latest_version = latest_available.version; + latest_version = registry.LatestAvailable(identifier, current_ksp_version)?.version; } catch (ModuleNotFoundKraken) { - latest_version = installed_version; } - InstalledVersion = installed_version != null ? installed_version.ToString() : "-"; - // Let's try to find the compatibility for this mod. If it's not in the registry at // all (because it's a DarkKAN mod) then this might fail. @@ -102,35 +144,18 @@ public GUIMod(CkanModule mod, IRegistryQuerier registry, KspVersionCriteria curr try { - latest_available_for_any_ksp = registry.LatestAvailable(mod.identifier, null); + latest_available_for_any_ksp = registry.LatestAvailable(identifier, null); } catch - { - // If we can't find the mod in the CKAN, but we've a CkanModule installed, then - // use that. - if (IsCKAN) - latest_available_for_any_ksp = (CkanModule) mod; - } + { } // If there's known information for this mod in any form, calculate the highest compatible // KSP. if (latest_available_for_any_ksp != null) { - KSPCompatibility = registry.LatestCompatibleKSP(mod.identifier)?.ToYalovString() + KSPCompatibility = registry.LatestCompatibleKSP(identifier)?.ToYalovString() ?? "Unknown"; - - // If the mod we have installed is *not* the mod we have installed, or we don't know - // what we have installed, indicate that an upgrade would be needed. - if (installed_version == null || !latest_available_for_any_ksp.version.IsEqualTo(installed_version)) - { - KSPCompatibilityLong = string.Format("{0} (using mod version {1})", - KSPCompatibility, latest_available_for_any_ksp.version); - - } - else - { - KSPCompatibilityLong = KSPCompatibility; - } + KSPCompatibilityLong = $"{KSPCompatibility} (using mod version {latest_available_for_any_ksp.version})"; } else { @@ -151,43 +176,9 @@ public GUIMod(CkanModule mod, IRegistryQuerier registry, KspVersionCriteria curr LatestVersion = "-"; } - KSPversion = ksp_version != null ? ksp_version.ToString() : "-"; - - Abstract = mod.@abstract; - // If we have a homepage provided, use that; otherwise use the spacedock page, curse page or the github repo so that users have somewhere to get more info than just the abstract. Homepage = "N/A"; - if (mod.resources != null) - { - if (mod.resources.homepage != null) - { - Homepage = mod.resources.homepage.ToString(); - } - else if (mod.resources.spacedock != null) - { - Homepage = mod.resources.spacedock.ToString(); - } - else if (mod.resources.curse != null) - { - Homepage = mod.resources.curse.ToString(); - } - else if (mod.resources.repository != null) - { - Homepage = mod.resources.repository.ToString(); - } - } - - Identifier = mod.identifier; - - DownloadSize = (mod.download_size == 0) - ? "N/A" - : CkanModule.FmtSize(mod.download_size); - - Abbrevation = new string(mod.name.Split(' '). - Where(s => s.Length > 0).Select(s => s[0]).ToArray()); - - UpdateIsCached(); } public void UpdateIsCached() diff --git a/GUI/Main.Designer.cs b/GUI/Main.Designer.cs index 9dccb6d63d..2e53872269 100644 --- a/GUI/Main.Designer.cs +++ b/GUI/Main.Designer.cs @@ -74,6 +74,7 @@ private void InitializeComponent() this.LatestVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.KSPCompatibility = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.SizeCol = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.InstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Description = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.ModListContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.reinstallToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -481,6 +482,7 @@ private void InitializeComponent() this.LatestVersion, this.KSPCompatibility, this.SizeCol, + this.InstallDate, this.Description}); this.ModList.ContextMenuStrip = this.ModListContextMenuStrip; this.ModList.Dock = System.Windows.Forms.DockStyle.Fill; @@ -561,6 +563,14 @@ private void InitializeComponent() this.SizeCol.ReadOnly = true; this.SizeCol.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Programmatic; // + // InstallDate + // + this.InstallDate.HeaderText = "Install Date"; + this.InstallDate.Name = "InstallDate"; + this.InstallDate.ReadOnly = true; + this.InstallDate.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Programmatic; + this.InstallDate.Width = 140; + // // Description // this.Description.HeaderText = "Description"; @@ -1147,6 +1157,7 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn LatestVersion; private System.Windows.Forms.DataGridViewTextBoxColumn KSPCompatibility; private System.Windows.Forms.DataGridViewTextBoxColumn SizeCol; + private System.Windows.Forms.DataGridViewTextBoxColumn InstallDate; private System.Windows.Forms.DataGridViewTextBoxColumn Description; private System.Windows.Forms.ContextMenuStrip ModListContextMenuStrip; private System.Windows.Forms.ToolStripMenuItem reinstallToolStripMenuItem; diff --git a/GUI/MainModList.cs b/GUI/MainModList.cs index f8bd12ec46..a01f413494 100644 --- a/GUI/MainModList.cs +++ b/GUI/MainModList.cs @@ -21,14 +21,12 @@ private void UpdateFilters(Main control) private IEnumerable _SortRowsByColumn(IEnumerable rows) { - // XXX: There should be a better way to identify checkbox columns than hardcoding their indices here - if (this.configuration.SortByColumnIndex < 2) + switch (this.configuration.SortByColumnIndex) { - return Sort(rows, CheckboxSorter); - } - else if (this.configuration.SortByColumnIndex == 7) - { - return Sort(rows, DownloadSizeSorter); + // XXX: There should be a better way to identify checkbox columns than hardcoding their indices here + case 0: case 1: return Sort(rows, CheckboxSorter); + case 7: return Sort(rows, DownloadSizeSorter); + case 8: return Sort(rows, InstallDateSorter); } return Sort(rows, DefaultSorter); } @@ -87,6 +85,17 @@ private long DownloadSizeSorter(DataGridViewRow row) return (row.Tag as GUIMod)?.ToCkanModule()?.download_size ?? 0; } + /// + /// Transforms a DataGridViewRow into a long representing the install date, + /// suitable for sorting. + /// The grid's default on first click is ascending, and sorting uninstalled mods to + /// the top is kind of useless, so we'll make this negative so ascending is useful. + /// + private long InstallDateSorter(DataGridViewRow row) + { + return -(row.Tag as GUIMod)?.InstallDate?.Ticks ?? 0; + } + private void _UpdateFilters() { if (ModList == null) return; @@ -139,20 +148,21 @@ private void _UpdateModsList(bool repo_updated, List mc) KspVersionCriteria versionCriteria = CurrentInstance.VersionCriteria(); IRegistryQuerier registry = RegistryManager.Instance(CurrentInstance).registry; - var gui_mods = new HashSet(registry.Available(versionCriteria) - .Select(m => new GUIMod(m, registry, versionCriteria))); - gui_mods.UnionWith(registry.Incompatible(versionCriteria) - .Select(m => new GUIMod(m, registry, versionCriteria, true))); - var installed = registry.InstalledModules - .Select(m => new GUIMod(m.Module, registry, versionCriteria)); - //Hashset does not define if add/unionwith replaces existing elements. - //In this case that could cause a CkanModule to be replaced by a Module. - //Hence the explicit checking - foreach (var mod in installed.Where(mod => !gui_mods.Contains(mod))) - { - gui_mods.Add(mod); - } + var gui_mods = new HashSet(); + gui_mods.UnionWith( + registry.InstalledModules + .Select(instMod => new GUIMod(instMod, registry, versionCriteria)) + ); + gui_mods.UnionWith( + registry.Available(versionCriteria) + .Select(m => new GUIMod(m, registry, versionCriteria)) + ); + gui_mods.UnionWith( + registry.Incompatible(versionCriteria) + .Select(m => new GUIMod(m, registry, versionCriteria, true)) + ); + var old_modules = mainModList.Modules.ToDictionary(m => m, m => m.IsIncompatible); if (repo_updated) { @@ -696,63 +706,77 @@ public IEnumerable ConstructModList(IEnumerable modules foreach (var mod in rowsToUpdate) { full_list_of_mod_rows.Remove(mod.Identifier); - var item = new DataGridViewRow {Tag = mod}; - - ModChange myChange = mc?.FindLast((ModChange ch) => ch.Mod.Identifier == mod.Identifier); - - var selecting = mod.IsInstallable() - ? (DataGridViewCell) new DataGridViewCheckBoxCell() { - Value = myChange == null ? mod.IsInstalled - : myChange.ChangeType == GUIModChangeType.Install ? true - : myChange.ChangeType == GUIModChangeType.Remove ? false - : mod.IsInstalled - } : new DataGridViewTextBoxCell() { - Value = mod.IsAutodetected ? "AD" : "-" - }; - - var updating = mod.IsInstallable() && mod.HasUpdate - ? (DataGridViewCell) new DataGridViewCheckBoxCell() { - Value = myChange == null ? false - : myChange.ChangeType == GUIModChangeType.Update ? true - : false - } : new DataGridViewTextBoxCell() { - Value = "-" - }; - - var name = new DataGridViewTextBoxCell {Value = mod.Name}; - var author = new DataGridViewTextBoxCell {Value = mod.Authors}; - - var installVersion = new DataGridViewTextBoxCell { - Value = - hideEpochs ? - (hideV ? ModuleInstaller.StripEpoch(ModuleInstaller.StripV(mod.InstalledVersion)) - : ModuleInstaller.StripEpoch(mod.InstalledVersion)) - : (hideV ? ModuleInstaller.StripV(mod.InstalledVersion) - : mod.InstalledVersion) + full_list_of_mod_rows.Add(mod.Identifier, MakeRow(mod, mc, hideEpochs, hideV)); + } + return full_list_of_mod_rows.Values; + } + + private DataGridViewRow MakeRow(GUIMod mod, List changes, bool hideEpochs = false, bool hideV = false) + { + DataGridViewRow item = new DataGridViewRow() {Tag = mod}; + + ModChange myChange = changes?.FindLast((ModChange ch) => ch.Mod.Identifier == mod.Identifier); + + var selecting = mod.IsInstallable() + ? (DataGridViewCell) new DataGridViewCheckBoxCell() + { + Value = myChange == null ? mod.IsInstalled + : myChange.ChangeType == GUIModChangeType.Install ? true + : myChange.ChangeType == GUIModChangeType.Remove ? false + : mod.IsInstalled + } + : new DataGridViewTextBoxCell() + { + Value = mod.IsAutodetected ? "AD" : "-" }; - var latestVersion = new DataGridViewTextBoxCell + var updating = mod.IsInstallable() && mod.HasUpdate + ? (DataGridViewCell) new DataGridViewCheckBoxCell() + { + Value = myChange == null ? false + : myChange.ChangeType == GUIModChangeType.Update ? true + : false + } + : new DataGridViewTextBoxCell() { - Value = - hideEpochs ? - (hideV ? ModuleInstaller.StripEpoch(ModuleInstaller.StripV(mod.LatestVersion)) - : ModuleInstaller.StripEpoch(mod.LatestVersion)) - : (hideV ? ModuleInstaller.StripV(mod.LatestVersion) - : mod.LatestVersion) + Value = "-" }; - var desc = new DataGridViewTextBoxCell {Value = mod.Abstract}; - var compat = new DataGridViewTextBoxCell {Value = mod.KSPCompatibility}; - var size = new DataGridViewTextBoxCell {Value = mod.DownloadSize}; + var name = new DataGridViewTextBoxCell() {Value = mod.Name}; + var author = new DataGridViewTextBoxCell() {Value = mod.Authors}; + + var installVersion = new DataGridViewTextBoxCell() + { + Value = hideEpochs + ? (hideV + ? ModuleInstaller.StripEpoch(ModuleInstaller.StripV(mod.InstalledVersion ?? "")) + : ModuleInstaller.StripEpoch(mod.InstalledVersion ?? "")) + : (hideV + ? ModuleInstaller.StripV(mod.InstalledVersion ?? "") + : mod.InstalledVersion ?? "") + }; - item.Cells.AddRange(selecting, updating, name, author, installVersion, latestVersion, compat, size, desc); + var latestVersion = new DataGridViewTextBoxCell() + { + Value = + hideEpochs ? + (hideV ? ModuleInstaller.StripEpoch(ModuleInstaller.StripV(mod.LatestVersion)) + : ModuleInstaller.StripEpoch(mod.LatestVersion)) + : (hideV ? ModuleInstaller.StripV(mod.LatestVersion) + : mod.LatestVersion) + }; - selecting.ReadOnly = selecting is DataGridViewTextBoxCell; - updating.ReadOnly = updating is DataGridViewTextBoxCell; + var compat = new DataGridViewTextBoxCell() { Value = mod.KSPCompatibility }; + var size = new DataGridViewTextBoxCell() { Value = mod.DownloadSize }; + var installDate = new DataGridViewTextBoxCell() { Value = mod.InstallDate }; + var desc = new DataGridViewTextBoxCell() { Value = mod.Abstract }; - full_list_of_mod_rows.Add(mod.Identifier, item); - } - return full_list_of_mod_rows.Values; + item.Cells.AddRange(selecting, updating, name, author, installVersion, latestVersion, compat, size, installDate, desc); + + selecting.ReadOnly = selecting is DataGridViewTextBoxCell; + updating.ReadOnly = updating is DataGridViewTextBoxCell; + + return item; } private bool IsNameInNameFilter(GUIMod mod)