diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b02bedffe..0b7e6bc2a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ All notable changes to this project will be documented in this file. - [GUI] Fix checkbox sorting (#3297 by: HebaruSan; reviewed: DasSkelett) - [GUI] Handle incompatible force-installed dependencies of recommendations (#3305 by: HebaruSan; reviewed: DasSkelett) - [Multiple] Don't warn about incompatible DLCs, fix conflict highlighting with DLC installed (#3304 by: HebaruSan; reviewed: DasSkelett) +- [Multiple] Fixes for GUI and .ckan-installed modules (#3307 by: DasSkelett; reviewed: HebaruSan) ### Internal diff --git a/ConsoleUI/ConsoleCKAN.cs b/ConsoleUI/ConsoleCKAN.cs index 0e34799f13..c8d2dbd38c 100644 --- a/ConsoleUI/ConsoleCKAN.cs +++ b/ConsoleUI/ConsoleCKAN.cs @@ -16,7 +16,7 @@ public class ConsoleCKAN { /// public ConsoleCKAN(GameInstanceManager mgr, string themeName, bool debug) { - if (ConsoleTheme.Themes.TryGetValue(themeName, out ConsoleTheme theme)) + if (ConsoleTheme.Themes.TryGetValue(themeName ?? "default", out ConsoleTheme theme)) { // GameInstanceManager only uses its IUser object to construct game instance objects, // which only use it to inform the user about the creation of the CKAN/ folder. @@ -40,7 +40,7 @@ public ConsoleCKAN(GameInstanceManager mgr, string themeName, bool debug) } } if (manager.CurrentInstance != null) { - new ModListScreen(manager, debug).Run(theme); + new ModListScreen(manager, debug, theme).Run(theme); } new ExitScreen().Run(theme); diff --git a/ConsoleUI/ModListScreen.cs b/ConsoleUI/ModListScreen.cs index 96c11a0de8..cbc5555375 100644 --- a/ConsoleUI/ModListScreen.cs +++ b/ConsoleUI/ModListScreen.cs @@ -17,7 +17,7 @@ public class ModListScreen : ConsoleScreen { /// /// Game instance manager object containing the current instance /// True if debug options should be available, false otherwise - public ModListScreen(GameInstanceManager mgr, bool dbg) + public ModListScreen(GameInstanceManager mgr, bool dbg, ConsoleTheme _theme) { debug = dbg; manager = mgr; @@ -25,7 +25,7 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) moduleList = new ConsoleListBox( 1, 4, -1, -2, - GetAllMods(), + GetAllMods(_theme), new List>() { new ConsoleListBoxColumn() { Header = "", @@ -205,7 +205,7 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) } return true; }); - + moduleList.AddTip("F8", "Mark auto-installed", () => moduleList.Selection != null && !moduleList.Selection.IsDLC && (!registry.InstalledModule(moduleList.Selection.identifier)?.AutoInstalled ?? false) @@ -265,7 +265,7 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) null, new ConsoleMenuOption("Refresh mod list", "F5, Ctrl+R", "Refresh the list of mods", - true, UpdateRegistry), + true, (ConsoleTheme th) => UpdateRegistry(th)), new ConsoleMenuOption("Upgrade all", "Ctrl+U", "Mark all available updates for installation", true, UpgradeAll, null, null, HasAnyUpgradeable()), @@ -328,7 +328,7 @@ protected override string CenterHeader() private bool ImportDownloads(ConsoleTheme theme) { DownloadImportDialog.ImportDownloads(theme, manager.CurrentInstance, manager.Cache, plan); - RefreshList(); + RefreshList(theme); return true; } @@ -393,7 +393,7 @@ private bool ViewSuggestions(ConsoleTheme theme) } } if (needRefresh) { - RefreshList(); + RefreshList(theme); } } else { RaiseError("Installed mods have no unsatisfied recommendations or suggestions."); @@ -414,7 +414,7 @@ private int daysSinceUpdated(string filename) return (DateTime.Now - File.GetLastWriteTime(filename)).Days; } - private bool UpdateRegistry(ConsoleTheme theme) + private bool UpdateRegistry(ConsoleTheme theme, bool showNewModsPrompt = true) { ProgressScreen ps = new ProgressScreen("Updating Registry", "Checking for updates"); LaunchSubScreen(theme, ps, (ConsoleTheme th) => { @@ -447,11 +447,11 @@ private bool UpdateRegistry(ConsoleTheme theme) } } }); - if (recent.Count > 0 && RaiseYesNoDialog(newModPrompt(recent.Count))) { + if (showNewModsPrompt && recent.Count > 0 && RaiseYesNoDialog(newModPrompt(recent.Count))) { searchBox.Clear(); moduleList.FilterString = searchBox.Value = "~n"; } - RefreshList(); + RefreshList(theme); return true; } @@ -481,7 +481,7 @@ private bool SelectInstall(ConsoleTheme theme) if (!prevInst.Equals(manager.CurrentInstance)) { plan.Reset(); registry = RegistryManager.Instance(manager.CurrentInstance).registry; - RefreshList(); + RefreshList(theme); } return true; } @@ -492,17 +492,23 @@ private bool EditAuthTokens(ConsoleTheme theme) return true; } - private void RefreshList() + private void RefreshList(ConsoleTheme theme) { - moduleList.SetData(GetAllMods(true)); + // In the constructor this is called while moduleList is being populated, just do nothing in this case. + // ModListScreen -> moduleList = (GetAllMods ...) -> UpdateRegistry -> RefreshList + moduleList?.SetData(GetAllMods(theme,true)); } private List allMods = null; - private List GetAllMods(bool force = false) + private List GetAllMods(ConsoleTheme theme, bool force = false) { ScanForMods(); if (allMods == null || force) { + if (!registry?.HasAnyAvailable() ?? false) + { + UpdateRegistry(theme, false); + } allMods = new List(registry.CompatibleModules(manager.CurrentInstance.VersionCriteria())); foreach (InstalledModule im in registry.InstalledModules) { CkanModule m = null; @@ -546,7 +552,7 @@ private bool Help(ConsoleTheme theme) private bool ApplyChanges(ConsoleTheme theme) { LaunchSubScreen(theme, new InstallScreen(manager, plan, debug)); - RefreshList(); + RefreshList(theme); return true; } @@ -598,9 +604,9 @@ private long totalInstalledDownloadSize() return total; } - private GameInstanceManager manager; - private IRegistryQuerier registry; - private bool debug; + private GameInstanceManager manager; + private Registry registry; + private bool debug; private ConsoleField searchBox; private ConsoleListBox moduleList; @@ -839,7 +845,7 @@ public enum InstallStatus { /// This mod is installed and not upgradeable or planned to be removed /// Installed, - + /// /// Like Installed, but can be auto-removed if depending mods are removed /// diff --git a/Core/ModuleInstaller.cs b/Core/ModuleInstaller.cs index 3c016494a9..e3d4009ff2 100644 --- a/Core/ModuleInstaller.cs +++ b/Core/ModuleInstaller.cs @@ -1347,7 +1347,7 @@ IRegistryQuerier registry { RelationshipResolver resolver = new RelationshipResolver( toInstall, - null, + toInstall.Select(m => registry.InstalledModule(m.identifier)?.Module).Where(m => m != null), opts, registry, ksp.VersionCriteria() ); diff --git a/Core/Net/NetAsyncDownloader.cs b/Core/Net/NetAsyncDownloader.cs index c31794bd45..f2367edd40 100644 --- a/Core/Net/NetAsyncDownloader.cs +++ b/Core/Net/NetAsyncDownloader.cs @@ -356,6 +356,8 @@ private void FileProgressReport(int index, int percent, long bytesDownloaded, lo foreach (NetAsyncDownloaderDownloadPart t in downloads.ToList()) { + if (t == null) + continue; if (t.bytesLeft > 0) { totalBytesPerSecond += t.bytesPerSecond; @@ -366,6 +368,9 @@ private void FileProgressReport(int index, int percent, long bytesDownloaded, lo } foreach (Net.DownloadTarget t in queuedDownloads.ToList()) { + // Somehow managed to get a NullRef for t here + if (t == null) + continue; totalBytesLeft += t.size; totalSize += t.size; } diff --git a/Core/Registry/IRegistryQuerier.cs b/Core/Registry/IRegistryQuerier.cs index 1a4e6e87bb..46b272e0f1 100644 --- a/Core/Registry/IRegistryQuerier.cs +++ b/Core/Registry/IRegistryQuerier.cs @@ -194,7 +194,7 @@ public static bool HasUpdate(this IRegistryQuerier querier, string identifier, G { RelationshipResolver resolver = new RelationshipResolver( new CkanModule[] { newest_version }, - null, + new CkanModule[] { querier.InstalledModule(identifier).Module }, new RelationshipResolverOptions() { with_recommends = false, diff --git a/Core/Relationships/RelationshipResolver.cs b/Core/Relationships/RelationshipResolver.cs index 87fd39ddca..9b45e04ee9 100644 --- a/Core/Relationships/RelationshipResolver.cs +++ b/Core/Relationships/RelationshipResolver.cs @@ -247,9 +247,9 @@ private void AddModulesToInstall(IEnumerable modules) { log.DebugFormat("Preparing to resolve relationships for {0} {1}", module.identifier, module.version); - //Need to check against installed mods and those to install. - var mods = modlist.Values.Concat(installed_modules).Where(listed_mod => listed_mod.ConflictsWith(module)); - foreach (CkanModule listed_mod in mods) + // Need to check against installed mods and those to install. + var conflictingModules = modlist.Values.Concat(installed_modules).Where(listed_mod => listed_mod.ConflictsWith(module)); + foreach (CkanModule listed_mod in conflictingModules) { if (options.proceed_with_inconsistencies) { diff --git a/GUI/Controls/AllModVersions.cs b/GUI/Controls/AllModVersions.cs index 2641c598a9..5586ca737a 100644 --- a/GUI/Controls/AllModVersions.cs +++ b/GUI/Controls/AllModVersions.cs @@ -122,6 +122,11 @@ public GUIMod SelectedModule visibleGuiModule.PropertyChanged += visibleGuiModule_PropertyChanged; } } + VersionsListView.Items.Clear(); + if (value == null) + { + return; + } // Get all the data; can put this in bg if slow GameInstance currentInstance = Main.Instance.Manager.CurrentInstance; @@ -139,16 +144,28 @@ public GUIMod SelectedModule } catch (ModuleNotFoundKraken) { - // No versions to be shown, abort and hope an auto refresh happens + // Identifier unknown to registry, maybe installed from local .ckan + allAvailableVersions = new Dictionary(); + } + + // Take the module associated with GUIMod, if any, and append it to the list if it's not already there. + var installedModule = value.InstalledMod?.Module; + if (installedModule != null && !allAvailableVersions.ContainsKey(installedModule)) + { + allAvailableVersions.Add(installedModule, installable(installer, installedModule, registry)); + } + + if (!allAvailableVersions.Any()) + { return; } + ModuleVersion installedVersion = registry.InstalledVersion(value.Identifier); // Update UI; must be in fg ignoreItemCheck = true; bool latestCompatibleVersionAlreadyFound = false; - VersionsListView.Items.Clear(); // Only show checkboxes for non-DLC modules VersionsListView.CheckBoxes = !value.ToModule().IsDLC; diff --git a/GUI/Controls/ManageMods.Designer.cs b/GUI/Controls/ManageMods.Designer.cs index 1e4ac0a7b5..294b8e574e 100644 --- a/GUI/Controls/ManageMods.Designer.cs +++ b/GUI/Controls/ManageMods.Designer.cs @@ -1,4 +1,6 @@ -namespace CKAN +using System.Windows.Forms; + +namespace CKAN { partial class ManageMods { @@ -98,6 +100,7 @@ private void InitializeComponent() this.FilterToolButton, this.NavBackwardToolButton, this.NavForwardToolButton}); + this.menuStrip2.CanOverflow = true; this.menuStrip2.Location = new System.Drawing.Point(0, 0); this.menuStrip2.Name = "menuStrip2"; this.menuStrip2.Size = new System.Drawing.Size(5876, 48); @@ -110,6 +113,7 @@ private void InitializeComponent() this.launchGameToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.launchGameToolStripMenuItem.Name = "launchGameToolStripMenuItem"; this.launchGameToolStripMenuItem.Size = new System.Drawing.Size(146, 56); + this.launchGameToolStripMenuItem.Overflow = ToolStripItemOverflow.AsNeeded; this.launchGameToolStripMenuItem.Click += new System.EventHandler(this.launchGameToolStripMenuItem_Click); resources.ApplyResources(this.launchGameToolStripMenuItem, "launchGameToolStripMenuItem"); // @@ -119,6 +123,7 @@ private void InitializeComponent() this.RefreshToolButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.RefreshToolButton.Name = "RefreshToolButton"; this.RefreshToolButton.Size = new System.Drawing.Size(114, 56); + this.RefreshToolButton.Overflow = ToolStripItemOverflow.AsNeeded; this.RefreshToolButton.Click += new System.EventHandler(this.RefreshToolButton_Click); resources.ApplyResources(this.RefreshToolButton, "RefreshToolButton"); // @@ -128,6 +133,7 @@ private void InitializeComponent() this.UpdateAllToolButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.UpdateAllToolButton.Name = "UpdateAllToolButton"; this.UpdateAllToolButton.Size = new System.Drawing.Size(232, 56); + this.UpdateAllToolButton.Overflow = ToolStripItemOverflow.AsNeeded; this.UpdateAllToolButton.Click += new System.EventHandler(this.MarkAllUpdatesToolButton_Click); resources.ApplyResources(this.UpdateAllToolButton, "UpdateAllToolButton"); // @@ -137,6 +143,7 @@ private void InitializeComponent() this.ApplyToolButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.ApplyToolButton.Name = "ApplyToolButton"; this.ApplyToolButton.Size = new System.Drawing.Size(173, 56); + this.ApplyToolButton.Overflow = ToolStripItemOverflow.AsNeeded; this.ApplyToolButton.Click += new System.EventHandler(this.ApplyToolButton_Click); resources.ApplyResources(this.ApplyToolButton, "ApplyToolButton"); // @@ -161,6 +168,7 @@ private void InitializeComponent() this.FilterToolButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.FilterToolButton.Name = "FilterToolButton"; this.FilterToolButton.Size = new System.Drawing.Size(201, 56); + this.FilterToolButton.Overflow = ToolStripItemOverflow.AsNeeded; resources.ApplyResources(this.FilterToolButton, "FilterToolButton"); // // FilterCompatibleButton @@ -253,6 +261,7 @@ private void InitializeComponent() this.NavBackwardToolButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.NavBackwardToolButton.Name = "NavBackwardToolButton"; this.NavBackwardToolButton.Size = new System.Drawing.Size(44, 56); + this.NavBackwardToolButton.Overflow = ToolStripItemOverflow.AsNeeded; this.NavBackwardToolButton.Click += new System.EventHandler(this.NavBackwardToolButton_Click); resources.ApplyResources(this.NavBackwardToolButton, "NavBackwardToolButton"); // @@ -262,6 +271,7 @@ private void InitializeComponent() this.NavForwardToolButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.NavForwardToolButton.Name = "NavForwardToolButton"; this.NavForwardToolButton.Size = new System.Drawing.Size(44, 56); + this.NavForwardToolButton.Overflow = ToolStripItemOverflow.AsNeeded; this.NavForwardToolButton.Click += new System.EventHandler(this.NavForwardToolButton_Click); resources.ApplyResources(this.NavForwardToolButton, "NavForwardToolButton"); // diff --git a/GUI/Controls/ManageMods.cs b/GUI/Controls/ManageMods.cs index 76eb2492a1..36106baa26 100644 --- a/GUI/Controls/ManageMods.cs +++ b/GUI/Controls/ManageMods.cs @@ -786,8 +786,21 @@ public void ClearChangeSet() { mod.SetInstallChecked(row, Installed, mod.IsInstalled); } + else if (mod.SelectedMod != mod.InstalledMod?.Module) + { + mod.SelectedMod = mod.InstalledMod?.Module; + } mod.SetUpgradeChecked(row, UpdateCol, false); mod.SetReplaceChecked(row, ReplaceCol, false); + // Marking a mod as AutoInstalled can immediately queue it for removal if there is no dependent mod. + // Reset the state of the AutoInstalled checkbox for these by deducing it from the changeset. + if (mod.InstalledMod != null && + ChangeSet.Contains(new ModChange(mod.InstalledMod?.Module, GUIModChangeType.Remove, + new SelectionReason.NoLongerUsed())) + ) + { + mod.SetAutoInstallChecked(row, AutoInstalled, false); + } } } diff --git a/GUI/Controls/ModInfo.cs b/GUI/Controls/ModInfo.cs index 714eeeb3fb..5084358d43 100644 --- a/GUI/Controls/ModInfo.cs +++ b/GUI/Controls/ModInfo.cs @@ -140,7 +140,7 @@ private void UpdateModInfo(GUIMod gui_module) Util.Invoke(MetadataModuleAuthorTextBox, () => MetadataModuleAuthorTextBox.Text = gui_module.Authors); Util.Invoke(MetadataIdentifierTextBox, () => MetadataIdentifierTextBox.Text = module.identifier); - Util.Invoke(MetadataModuleReleaseStatusTextBox, () => + Util.Invoke(MetadataModuleReleaseStatusTextBox, () => { if (module.release_status == null) { diff --git a/GUI/Controls/Wait.Designer.cs b/GUI/Controls/Wait.Designer.cs index 51b994eca0..8f6715cb71 100644 --- a/GUI/Controls/Wait.Designer.cs +++ b/GUI/Controls/Wait.Designer.cs @@ -37,18 +37,19 @@ private void InitializeComponent() this.BottomButtonPanel = new System.Windows.Forms.Panel(); this.CancelCurrentActionButton = new System.Windows.Forms.Button(); this.RetryCurrentActionButton = new System.Windows.Forms.Button(); + this.OkButton = new System.Windows.Forms.Button(); this.SuspendLayout(); - // + // // TopPanel - // + // this.TopPanel.Controls.Add(this.MessageTextBox); this.TopPanel.Controls.Add(this.DialogProgressBar); this.TopPanel.Dock = System.Windows.Forms.DockStyle.Top; this.TopPanel.Name = "TopPanel"; this.TopPanel.Size = new System.Drawing.Size(500, 85); - // + // // MessageTextBox - // + // this.MessageTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.MessageTextBox.BackColor = System.Drawing.SystemColors.Control; this.MessageTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -62,9 +63,9 @@ private void InitializeComponent() this.MessageTextBox.TabIndex = 0; this.MessageTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; resources.ApplyResources(this.MessageTextBox, "MessageTextBox"); - // + // // DialogProgressBar - // + // this.DialogProgressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.DialogProgressBar.Location = new System.Drawing.Point(5, 45); @@ -75,9 +76,9 @@ private void InitializeComponent() this.DialogProgressBar.Size = new System.Drawing.Size(490, 25); this.DialogProgressBar.Style = System.Windows.Forms.ProgressBarStyle.Marquee; this.DialogProgressBar.TabIndex = 1; - // + // // LogTextBox - // + // this.LogTextBox.Dock = System.Windows.Forms.DockStyle.Fill; this.LogTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.LogTextBox.Location = new System.Drawing.Point(14, 89); @@ -89,41 +90,54 @@ private void InitializeComponent() this.LogTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.LogTextBox.Size = new System.Drawing.Size(500, 400); this.LogTextBox.TabIndex = 2; - // + // // BottomButtonPanel - // - this.BottomButtonPanel.Controls.Add(this.CancelCurrentActionButton); + // this.BottomButtonPanel.Controls.Add(this.RetryCurrentActionButton); + this.BottomButtonPanel.Controls.Add(this.CancelCurrentActionButton); + this.BottomButtonPanel.Controls.Add(this.OkButton); this.BottomButtonPanel.Dock = System.Windows.Forms.DockStyle.Bottom; this.BottomButtonPanel.Name = "BottomButtonPanel"; this.BottomButtonPanel.Size = new System.Drawing.Size(500, 40); - // + // // RetryCurrentActionButton - // + // this.RetryCurrentActionButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.RetryCurrentActionButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.RetryCurrentActionButton.Location = new System.Drawing.Point(266, 5); + this.RetryCurrentActionButton.Location = new System.Drawing.Point(149, 5); this.RetryCurrentActionButton.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.RetryCurrentActionButton.Name = "RetryCurrentActionButton"; this.RetryCurrentActionButton.Size = new System.Drawing.Size(112, 30); this.RetryCurrentActionButton.TabIndex = 3; this.RetryCurrentActionButton.Click += new System.EventHandler(this.RetryCurrentActionButton_Click); resources.ApplyResources(this.RetryCurrentActionButton, "RetryCurrentActionButton"); - // + // // CancelCurrentActionButton - // + // this.CancelCurrentActionButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.CancelCurrentActionButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.CancelCurrentActionButton.Location = new System.Drawing.Point(383, 5); + this.CancelCurrentActionButton.Location = new System.Drawing.Point(266, 5); this.CancelCurrentActionButton.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.CancelCurrentActionButton.Name = "CancelCurrentActionButton"; this.CancelCurrentActionButton.Size = new System.Drawing.Size(112, 30); this.CancelCurrentActionButton.TabIndex = 4; this.CancelCurrentActionButton.Click += new System.EventHandler(this.CancelCurrentActionButton_Click); resources.ApplyResources(this.CancelCurrentActionButton, "CancelCurrentActionButton"); - // + // + // OkButton + // + this.OkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OkButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.OkButton.Location = new System.Drawing.Point(383, 5); + this.OkButton.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.OkButton.Name = "OkButton"; + this.OkButton.Size = new System.Drawing.Size(112, 30); + this.OkButton.TabIndex = 5; + this.OkButton.Click += new System.EventHandler(this.OkButton_Click); + resources.ApplyResources(this.OkButton, "OkButton"); + // // Wait - // + // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; this.Controls.Add(this.LogTextBox); this.Controls.Add(this.TopPanel); @@ -146,5 +160,6 @@ private void InitializeComponent() private System.Windows.Forms.Panel BottomButtonPanel; private System.Windows.Forms.Button RetryCurrentActionButton; private System.Windows.Forms.Button CancelCurrentActionButton; + private System.Windows.Forms.Button OkButton; } } diff --git a/GUI/Controls/Wait.cs b/GUI/Controls/Wait.cs index b2016bfb2a..36bda98f82 100644 --- a/GUI/Controls/Wait.cs +++ b/GUI/Controls/Wait.cs @@ -17,6 +17,7 @@ public Wait() public event Action OnRetry; public event Action OnCancel; + public event Action OnOk; public bool RetryEnabled { @@ -199,6 +200,7 @@ public void Reset(bool cancelable) ProgressIndeterminate = true; RetryCurrentActionButton.Enabled = false; CancelCurrentActionButton.Enabled = cancelable; + OkButton.Enabled = false; MessageTextBox.Text = Properties.Resources.MainWaitPleaseWait; }); } @@ -212,6 +214,7 @@ public void Finish(bool success) ProgressIndeterminate = false; RetryCurrentActionButton.Enabled = !success; CancelCurrentActionButton.Enabled = false; + OkButton.Enabled = true; }); } @@ -250,5 +253,13 @@ private void CancelCurrentActionButton_Click(object sender, EventArgs e) Util.Invoke(this, () => CancelCurrentActionButton.Enabled = false); } + + private void OkButton_Click(object sender, EventArgs e) + { + if (OnOk != null) + { + OnOk(); + } + } } } diff --git a/GUI/Controls/Wait.resx b/GUI/Controls/Wait.resx index 4ac4273fb8..e273d4364b 100644 --- a/GUI/Controls/Wait.resx +++ b/GUI/Controls/Wait.resx @@ -119,5 +119,6 @@ Cancel Retry + OK Waiting for operation to complete diff --git a/GUI/Dialogs/ManageGameInstancesDialog.cs b/GUI/Dialogs/ManageGameInstancesDialog.cs index 2158b625d7..4a04afafb0 100644 --- a/GUI/Dialogs/ManageGameInstancesDialog.cs +++ b/GUI/Dialogs/ManageGameInstancesDialog.cs @@ -19,7 +19,7 @@ public partial class ManageGameInstancesDialog : Form Filter = GameFolderFilter(Main.Instance.Manager), Multiselect = false }; - + /// /// Generate filter string for OpenFileDialog /// @@ -213,7 +213,7 @@ private void GameInstancesListView_Click(object sender, MouseEventArgs e) private void OpenDirectoryMenuItem_Click(object sender, EventArgs e) { - string path = GameInstancesListView.SelectedItems[0].SubItems[2].Text; + string path = _manager.Instances[(string) GameInstancesListView.SelectedItems[0].Tag].GameDir(); if (!Directory.Exists(path)) { diff --git a/GUI/Main/Main.Designer.cs b/GUI/Main/Main.Designer.cs index 2fb74ff161..17e51b02fe 100644 --- a/GUI/Main/Main.Designer.cs +++ b/GUI/Main/Main.Designer.cs @@ -401,9 +401,9 @@ private void InitializeComponent() this.ManageModsTabPage.Size = new System.Drawing.Size(1536, 948); this.ManageModsTabPage.TabIndex = 3; resources.ApplyResources(this.ManageModsTabPage, "ManageModsTabPage"); - // + // // ManageMods - // + // this.ManageMods.Dock = System.Windows.Forms.DockStyle.Fill; this.ManageMods.Location = new System.Drawing.Point(0, 0); this.ManageMods.Margin = new System.Windows.Forms.Padding(0,0,0,0); @@ -467,6 +467,7 @@ private void InitializeComponent() this.Wait.TabIndex = 32; this.Wait.OnRetry += Wait_OnRetry; this.Wait.OnCancel += Wait_OnCancel; + this.Wait.OnOk += Wait_OnOk; // // ChooseRecommendedModsTabPage // diff --git a/GUI/Main/MainChangeset.cs b/GUI/Main/MainChangeset.cs index db2935f90c..51d59d51cd 100644 --- a/GUI/Main/MainChangeset.cs +++ b/GUI/Main/MainChangeset.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using System.Collections.Generic; using System.Windows.Forms; @@ -37,13 +38,22 @@ private void Changeset_OnConfirmChanges() // Using the changeset passed in can cause issues with versions. // An example is Mechjeb for FAR at 25/06/2015 with a 1.0.2 install. // TODO Work out why this is. - installWorker.RunWorkerAsync( - new KeyValuePair, RelationshipResolverOptions>( - ManageMods.mainModList.ComputeUserChangeSet(RegistryManager.Instance(Main.Instance.CurrentInstance).registry).ToList(), - RelationshipResolver.DependsOnlyOpts() - ) - ); + try + { + installWorker.RunWorkerAsync( + new KeyValuePair, RelationshipResolverOptions>( + ManageMods.mainModList + .ComputeUserChangeSet(RegistryManager.Instance(Main.Instance.CurrentInstance).registry) + .ToList(), + RelationshipResolver.DependsOnlyOpts() + ) + ); + } + catch (InvalidOperationException) + { + // Thrown if it's already busy, can happen if the user fouble-clicks the button. Ignore it. + // More thread-safe than checking installWorker.IsBusy beforehand. + } } - } } diff --git a/GUI/Main/MainInstall.cs b/GUI/Main/MainInstall.cs index e879dd83d4..09ed64db22 100644 --- a/GUI/Main/MainInstall.cs +++ b/GUI/Main/MainInstall.cs @@ -142,6 +142,8 @@ out Dictionary> supporters if (installCanceled) { + Util.Invoke(this, () => Enabled = true); + Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair(false, opts.Key); return; @@ -236,6 +238,8 @@ out Dictionary> supporters { // User cancelled, get out tabController.ShowTab("ManageModsTabPage"); + Util.Invoke(this, () => Enabled = true); + Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); e.Result = new KeyValuePair(false, opts.Key); return; } @@ -291,7 +295,11 @@ private void OnModInstalled(CkanModule mod) private void PostInstallMods(object sender, RunWorkerCompletedEventArgs e) { - tabController.SetTabLock(false); + okCallback = () => + { + ManageMods.UpdateModsList(null); + okCallback = null; + }; if (e.Error != null) { @@ -410,7 +418,10 @@ private void PostInstallMods(object sender, RunWorkerCompletedEventArgs e) } } - // install successful + Util.Invoke(this, () => Enabled = true); + Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); + tabController.SetTabLock(false); + AddStatusMessage(Properties.Resources.MainInstallSuccess); HideWaitDialog(true); } @@ -434,9 +445,6 @@ private void PostInstallMods(object sender, RunWorkerCompletedEventArgs e) } } } - - Util.Invoke(this, () => Enabled = true); - Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); } } } diff --git a/GUI/Main/MainWait.cs b/GUI/Main/MainWait.cs index eb23a69c19..bddfaf3334 100644 --- a/GUI/Main/MainWait.cs +++ b/GUI/Main/MainWait.cs @@ -6,6 +6,7 @@ namespace CKAN public partial class Main { private Action cancelCallback; + private Action okCallback; public void ShowWaitDialog(bool cancelable = true) { @@ -87,5 +88,16 @@ public void Wait_OnCancel() cancelCallback(); } } + + public void Wait_OnOk() + { + if (okCallback != null) + { + okCallback(); + } + Util.Invoke(this, () => Enabled = true); + Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); + tabController.SetTabLock(false); + } } } diff --git a/GUI/Model/GUIMod.cs b/GUI/Model/GUIMod.cs index b45152d09d..6737390908 100644 --- a/GUI/Model/GUIMod.cs +++ b/GUI/Model/GUIMod.cs @@ -12,7 +12,7 @@ public sealed class GUIMod : INotifyPropertyChanged { private CkanModule Mod { get; set; } private CkanModule LatestCompatibleMod { get; set; } - private InstalledModule InstalledMod { get; set; } + public InstalledModule InstalledMod { get; private set; } /// /// The module of the checkbox that is checked in the MainAllModVersions list if any, @@ -141,6 +141,8 @@ public GUIMod(InstalledModule instMod, IRegistryQuerier registry, GameVersionCri { LatestVersion = InstalledVersion; } + // For mods not known to the registry LatestCompatibleMod is null, however the installed module might be compatible + IsIncompatible = incompatible ?? LatestCompatibleMod == null && !instMod.Module.IsCompatibleKSP(current_game_version); } /// @@ -268,6 +270,12 @@ public void UpdateIsCached() IsCached = Main.Instance.Manager.Cache.IsMaybeCachedZip(Mod); } + /// + /// Get the CkanModule associated with this GUIMod. + /// See for a method that doesn't throw. + /// + /// The CkanModule associated with this GUIMod + /// Thrown if no CkanModule is associated public CkanModule ToCkanModule() { if (!IsCKAN) @@ -276,6 +284,10 @@ public CkanModule ToCkanModule() return mod; } + /// + /// Get the CkanModule associated with this GUIMod. + /// + /// The CkanModule associated with this GUIMod or null if there is none public CkanModule ToModule() { return Mod;