public void SetUp() { _testModule = TestData.DogeCoinFlag_101_module(); _instance = new DisposableKSP(); _nullUser = new NullUser(); _config = new FakeConfiguration(_instance.KSP, _instance.KSP.Name); _manager = new GameInstanceManager(_nullUser, _config); _registryManager = CKAN.RegistryManager.Instance(_instance.KSP); _registry = _registryManager.registry; _installer = CKAN.ModuleInstaller.GetInstance(_instance.KSP, _manager.Cache, _nullUser); _gameDir = _instance.KSP.GameDir(); _gameDataDir = _instance.KSP.game.PrimaryModDirectory(_instance.KSP); _registry.AddAvailable(_testModule); var testModFile = TestData.DogeCoinFlagZip(); _manager.Cache.Store(_testModule, testModFile); HashSet <string> possibleConfigOnlyDirs = null; _installer.InstallList( new List <string>() { _testModule.identifier }, new RelationshipResolverOptions(), _registryManager, ref possibleConfigOnlyDirs ); }
// Constructor private ModuleInstaller(KSP ksp, IUser user) { User = user; this.ksp = ksp; registry_manager = RegistryManager.Instance(ksp); log.DebugFormat("Creating ModuleInstaller for {0}", ksp.GameDir()); }
public void SetUp() { _testModule = TestData.DogeCoinFlag_101_module(); _nullUser = new NullUser(); _manager = new KSPManager(_nullUser); _instance = new DisposableKSP(); _registryManager = CKAN.RegistryManager.Instance(_instance.KSP); _registry = _registryManager.registry; _installer = CKAN.ModuleInstaller.GetInstance(_instance.KSP, _manager.Cache, _nullUser); _gameDataDir = _instance.KSP.GameData(); _registry.AddAvailable(_testModule); var testModFile = TestData.DogeCoinFlagZip(); _manager.Cache.Store(_testModule, testModFile); _installer.InstallList( new List <string>() { _testModule.identifier }, new RelationshipResolverOptions(), _registryManager ); }
public void Setup() { ksp = new DisposableKSP(); manager = CKAN.RegistryManager.Instance(ksp.KSP); registry = manager.registry; registry.ClearDlls(); registry.Installed().Clear(); }
public static int Update(RegistryManager registry_manager, KSP ksp, IUser user, Boolean clear = true, string repo = null) { if (repo == null) { return Update(registry_manager, ksp, user, clear, (Uri)null); } return Update(registry_manager, ksp, user, clear, new Uri(repo)); }
public void Setup() { ksp = new DisposableKSP(); manager = CKAN.RegistryManager.Instance(ksp.KSP); registry = manager.registry; registry.ClearDlls(); registry.Installed().Clear(); CKAN.Repo.Update(manager, ksp.KSP, new NullUser(), TestData.TestKANZip()); }
/// <summary> /// Returns an instance of the registry manager for the KSP install. /// The file `registry.json` is assumed. /// </summary> public static RegistryManager Instance(KSP ksp) { string directory = ksp.CkanDir(); if (!singleton.ContainsKey(directory)) { log.DebugFormat("Preparing to load registry at {0}", directory); singleton[directory] = new RegistryManager(directory, ksp); } return singleton[directory]; }
public static int Update(RegistryManager registry_manager, KSP ksp, IUser user, Boolean clear = true, Uri repo = null) { // Use our default repo, unless we've been told otherwise. if (repo == null) { repo = default_ckan_repo; } UpdateRegistry(repo, registry_manager.registry, ksp, user, clear); // Save our changes! registry_manager.Save(); // Return how many we got! return registry_manager.registry.Available(ksp.Version()).Count; }
/// <summary> /// Download and update the local CKAN meta-info. /// Optionally takes a URL to the zipfile repo to download. /// Returns the number of unique modules updated. /// </summary> public static int UpdateAllRepositories(RegistryManager registry_manager, KSP ksp, IUser user) { // If we handle multiple repositories, we will call ClearRegistry() ourselves... registry_manager.registry.ClearAvailable(); // TODO this should already give us a pre-sorted list SortedDictionary<string, Repository> sortedRepositories = registry_manager.registry.Repositories; foreach (KeyValuePair<string, Repository> repository in sortedRepositories) { log.InfoFormat("About to update {0}", repository.Value.name); UpdateRegistry(repository.Value.uri, registry_manager.registry, ksp, user, false); } // Save our changes. registry_manager.Save(); // Return how many we got! return registry_manager.registry.Available(ksp.Version()).Count; }
public void Setup() { manager = new KSPManager(new NullUser()); // Give us a registry to play with. ksp = new DisposableKSP(); registry_manager = CKAN.RegistryManager.Instance(ksp.KSP); registry = registry_manager.registry; registry.ClearDlls(); registry.Installed().Clear(); // Make sure we have a registry we can use. CKAN.Repo.Update(registry_manager, ksp.KSP, new NullUser(), TestData.TestKANZip()); // Ready our downloader. async = new CKAN.NetAsyncModulesDownloader(new NullUser(), manager.Cache); // General shortcuts cache = manager.Cache; }
private void _UpdateModsList(IEnumerable <ModChange> mc, Dictionary <string, bool> old_modules = null) { log.Info("Updating the mod list"); ResetProgress(); tabController.RenameTab("WaitTabPage", Properties.Resources.MainModListWaitTitle); ShowWaitDialog(false); tabController.SetTabLock(true); Util.Invoke(this, SwitchEnabledState); ClearLog(); AddLogMessage(Properties.Resources.MainModListLoadingRegistry); KspVersionCriteria versionCriteria = CurrentInstance.VersionCriteria(); IRegistryQuerier registry = RegistryManager.Instance(CurrentInstance).registry; AddLogMessage(Properties.Resources.MainModListLoadingInstalled); var gui_mods = new HashSet <GUIMod>(); gui_mods.UnionWith( registry.InstalledModules .Select(instMod => new GUIMod(instMod, registry, versionCriteria)) ); AddLogMessage(Properties.Resources.MainModListLoadingAvailable); gui_mods.UnionWith( registry.Available(versionCriteria) .Select(m => new GUIMod(m, registry, versionCriteria)) ); AddLogMessage(Properties.Resources.MainModListLoadingIncompatible); gui_mods.UnionWith( registry.Incompatible(versionCriteria) .Select(m => new GUIMod(m, registry, versionCriteria, true)) ); AddLogMessage(Properties.Resources.MainModListPreservingNew); if (old_modules != null) { foreach (GUIMod gm in gui_mods) { if (old_modules.TryGetValue(gm.Identifier, out bool oldIncompat)) { // Found it; check if newly compatible if (!gm.IsIncompatible && oldIncompat) { gm.IsNew = true; } } else { // Newly indexed, show regardless of compatibility gm.IsNew = true; } } } else { // Copy the new mod flag from the old list. var old_new_mods = new HashSet <GUIMod>( mainModList.Modules.Where(m => m.IsNew)); foreach (var gui_mod in gui_mods.Where(m => old_new_mods.Contains(m))) { gui_mod.IsNew = true; } } AddLogMessage(Properties.Resources.MainModListPopulatingList); // Update our mod listing mainModList.ConstructModList(gui_mods.ToList(), mc, configuration.HideEpochs, configuration.HideV); mainModList.Modules = new ReadOnlyCollection <GUIMod>( mainModList.full_list_of_mod_rows.Values.Select(row => row.Tag as GUIMod).ToList()); UpdateChangeSetAndConflicts(registry); AddLogMessage(Properties.Resources.MainModListUpdatingFilters); var has_any_updates = gui_mods.Any(mod => mod.HasUpdate); var has_any_installed = gui_mods.Any(mod => mod.IsInstalled); var has_any_replacements = gui_mods.Any(mod => mod.IsInstalled && mod.HasReplacement); //TODO Consider using smart enumeration pattern so stuff like this is easier Util.Invoke(menuStrip2, () => { FilterToolButton.DropDownItems[0].Text = String.Format(Properties.Resources.MainModListCompatible, mainModList.CountModsByFilter(GUIModFilter.Compatible)); FilterToolButton.DropDownItems[1].Text = String.Format(Properties.Resources.MainModListInstalled, mainModList.CountModsByFilter(GUIModFilter.Installed)); FilterToolButton.DropDownItems[2].Text = String.Format(Properties.Resources.MainModListUpgradeable, mainModList.CountModsByFilter(GUIModFilter.InstalledUpdateAvailable)); FilterToolButton.DropDownItems[3].Text = String.Format(Properties.Resources.MainModListReplaceable, mainModList.CountModsByFilter(GUIModFilter.Replaceable)); FilterToolButton.DropDownItems[4].Text = String.Format(Properties.Resources.MainModListCached, mainModList.CountModsByFilter(GUIModFilter.Cached)); FilterToolButton.DropDownItems[5].Text = String.Format(Properties.Resources.MainModListNewlyCompatible, mainModList.CountModsByFilter(GUIModFilter.NewInRepository)); FilterToolButton.DropDownItems[6].Text = String.Format(Properties.Resources.MainModListNotInstalled, mainModList.CountModsByFilter(GUIModFilter.NotInstalled)); FilterToolButton.DropDownItems[7].Text = String.Format(Properties.Resources.MainModListIncompatible, mainModList.CountModsByFilter(GUIModFilter.Incompatible)); FilterToolButton.DropDownItems[8].Text = String.Format(Properties.Resources.MainModListAll, mainModList.CountModsByFilter(GUIModFilter.All)); UpdateAllToolButton.Enabled = has_any_updates; }); UpdateFilters(this); // Hide update and replacement columns if not needed. // Write it to the configuration, else they are hidden agian after a filter change. // After the update / replacement, they are hidden again. Util.Invoke(ModList, () => { ModList.Columns["UpdateCol"].Visible = has_any_updates; ModList.Columns["AutoInstalled"].Visible = has_any_installed && !configuration.HiddenColumnNames.Contains("AutoInstalled"); ModList.Columns["ReplaceCol"].Visible = has_any_replacements; }); AddLogMessage(Properties.Resources.MainModListUpdatingTray); UpdateTrayInfo(); HideWaitDialog(true); tabController.HideTab("WaitTabPage"); tabController.SetTabLock(false); Util.Invoke(this, SwitchEnabledState); Util.Invoke(this, () => Main.Instance.ModList.Focus()); }
/// <summary> /// Download and update the local CKAN meta-info. /// Optionally takes a URL to the zipfile repo to download. /// </summary> public static RepoUpdateResult UpdateAllRepositories(RegistryManager registry_manager, GameInstance ksp, NetModuleCache cache, IUser user) { SortedDictionary <string, Repository> sortedRepositories = registry_manager.registry.Repositories; user.RaiseProgress("Checking for updates", 0); if (sortedRepositories.Values.All(repo => !string.IsNullOrEmpty(repo.last_server_etag) && repo.last_server_etag == Net.CurrentETag(repo.uri))) { user.RaiseProgress("Already up to date", 100); user.RaiseMessage("No changes since last update"); return(RepoUpdateResult.NoChanges); } List <CkanModule> allAvail = new List <CkanModule>(); int index = 0; foreach (KeyValuePair <string, Repository> repository in sortedRepositories) { user.RaiseProgress($"Updating {repository.Value.name}", 10 + 80 * index / sortedRepositories.Count); SortedDictionary <string, int> downloadCounts; string newETag; List <CkanModule> avail = UpdateRegistry(repository.Value.uri, ksp, user, out downloadCounts, out newETag); registry_manager.registry.SetDownloadCounts(downloadCounts); if (avail == null) { // Report failure if any repo fails, rather than losing half the list. // UpdateRegistry will have alerted the user to specific errors already. return(RepoUpdateResult.Failed); } else { // Merge all the lists allAvail.AddRange(avail); repository.Value.last_server_etag = newETag; user.RaiseMessage("Updated {0}", repository.Value.name); } ++index; } // Save allAvail to the registry if we found anything if (allAvail.Count > 0) { user.RaiseProgress("Saving modules to registry", 90); using (var transaction = CkanTransaction.CreateTransactionScope()) { // Save our changes. registry_manager.registry.SetAllAvailable(allAvail); registry_manager.Save(enforce_consistency: false); transaction.Complete(); } ShowUserInconsistencies(registry_manager.registry, user); List <CkanModule> metadataChanges = GetChangedInstalledModules(registry_manager.registry); if (metadataChanges.Count > 0) { HandleModuleChanges(metadataChanges, user, ksp, cache, registry_manager); } // Registry.CompatibleModules is slow, just return success, // caller can check it if it's really needed user.RaiseProgress("Registry saved", 100); user.RaiseMessage("Repositories updated"); return(RepoUpdateResult.Updated); } else { // Return failure return(RepoUpdateResult.Failed); } }
public Main(string[] cmdlineArgs, KSPManager mgr, GUIUser user, bool showConsole) { log.Info("Starting the GUI"); commandLineArgs = cmdlineArgs; manager = mgr ?? new KSPManager(user); currentUser = user; controlFactory = new ControlFactory(); Instance = this; mainModList = new MainModList(source => UpdateFilters(this), TooManyModsProvide, user); // History is read-only until the UI is started. We switch // out of it at the end of OnLoad() when we call NavInit(). navHistory = new NavigationHistory <GUIMod> { IsReadOnly = true }; InitializeComponent(); // Replace mono's broken, ugly toolstrip renderer if (Platform.IsMono) { menuStrip1.Renderer = new FlatToolStripRenderer(); menuStrip2.Renderer = new FlatToolStripRenderer(); fileToolStripMenuItem.DropDown.Renderer = new FlatToolStripRenderer(); settingsToolStripMenuItem.DropDown.Renderer = new FlatToolStripRenderer(); helpToolStripMenuItem.DropDown.Renderer = new FlatToolStripRenderer(); FilterToolButton.DropDown.Renderer = new FlatToolStripRenderer(); minimizedContextMenuStrip.Renderer = new FlatToolStripRenderer(); ModListContextMenuStrip.Renderer = new FlatToolStripRenderer(); ModListHeaderContextMenuStrip.Renderer = new FlatToolStripRenderer(); } // Initialize all user interaction dialogs. RecreateDialogs(); // We want to check if our current instance is null first, // as it may have already been set by a command-line option. if (CurrentInstance == null && manager.GetPreferredInstance() == null) { Hide(); var result = new ManageKspInstances(!actuallyVisible).ShowDialog(); if (result == DialogResult.Cancel || result == DialogResult.Abort) { Application.Exit(); return; } } configuration = Configuration.LoadOrCreateConfiguration ( Path.Combine(CurrentInstance.CkanDir(), "GUIConfig.xml") ); // Check if there is any other instances already running. // This is not entirely necessary, but we can show a nicer error message this way. try { #pragma warning disable 219 var lockedReg = RegistryManager.Instance(CurrentInstance).registry; #pragma warning restore 219 } catch (RegistryInUseKraken kraken) { errorDialog.ShowErrorDialog(kraken.ToString()); return; } FilterToolButton.MouseHover += (sender, args) => FilterToolButton.ShowDropDown(); launchKSPToolStripMenuItem.MouseHover += (sender, args) => launchKSPToolStripMenuItem.ShowDropDown(); ApplyToolButton.MouseHover += (sender, args) => ApplyToolButton.ShowDropDown(); ModList.CurrentCellDirtyStateChanged += ModList_CurrentCellDirtyStateChanged; ModList.CellValueChanged += ModList_CellValueChanged; tabController = new TabController(MainTabControl); tabController.ShowTab("ManageModsTabPage"); if (!showConsole) { Util.HideConsoleWindow(); } // Disable the modinfo controls until a mod has been choosen. This has an effect if the modlist is empty. ActiveModInfo = null; // WinForms on Mac OS X has a nasty bug where the UI thread hogs the CPU, // making our download speeds really slow unless you move the mouse while // downloading. Yielding periodically addresses that. // https://bugzilla.novell.com/show_bug.cgi?id=663433 if (Platform.IsMac) { var timer = new Timer { Interval = 2 }; timer.Tick += (sender, e) => { Thread.Yield(); }; timer.Start(); } // Set the window name and class for X11 if (Platform.IsX11) { HandleCreated += (sender, e) => X11.SetWMClass("CKAN", "CKAN", Handle); } Application.Run(this); var registry = RegistryManager.Instance(Manager.CurrentInstance); registry?.Dispose(); }
private TreeNode UpdateModDependencyGraphRecursively(TreeNode parentNode, CkanModule module, RelationshipType relationship, int depth, bool virtualProvides = false) { if (module == null || (depth > 0 && dependencyGraphRootModule == module) || (alreadyVisited.Contains(module))) { return(null); } alreadyVisited.Add(module); string nodeText = module.name; if (virtualProvides) { nodeText = String.Format("provided by - {0}", module.name); } var node = parentNode == null ? new TreeNode(nodeText) : parentNode.Nodes.Add(nodeText); IEnumerable <RelationshipDescriptor> relationships = null; switch (relationship) { case RelationshipType.Depends: relationships = module.depends; break; case RelationshipType.Recommends: relationships = module.recommends; break; case RelationshipType.Suggests: relationships = module.suggests; break; case RelationshipType.Supports: relationships = module.supports; break; } if (relationships == null) { return(node); } foreach (RelationshipDescriptor dependency in relationships) { Registry registry = RegistryManager.Instance(manager.CurrentInstance).registry; try { try { var dependencyModule = registry.LatestAvailable (dependency.name, manager.CurrentInstance.Version()); UpdateModDependencyGraphRecursively(node, dependencyModule, relationship, depth + 1); } catch (ModuleNotFoundKraken) { List <CkanModule> dependencyModules = registry.LatestAvailableWithProvides (dependency.name, manager.CurrentInstance.Version()); if (dependencyModules == null) { continue; } var newNode = node.Nodes.Add(dependency.name + " (virtual)"); newNode.ForeColor = Color.Gray; foreach (var dep in dependencyModules) { UpdateModDependencyGraphRecursively(newNode, dep, relationship, depth + 1, true); } } } catch (Exception) { } } if (virtualProvides) { node.Collapse(true); } else { node.ExpandAll(); } return(node); }
/// <summary> /// Resolve differences between installed and available metadata for given ModuleInstaller /// </summary> /// <param name="metadataChanges">List of modules that changed</param> /// <param name="user">Object for user interaction callbacks</param> /// <param name="ksp">Game instance</param> /// <param name="cache">Cacne object for mod downloads</param> /// <param name="registry_manager">Manager that holds our game instances</param> private static void HandleModuleChanges(List <CkanModule> metadataChanges, IUser user, GameInstance ksp, NetModuleCache cache, RegistryManager registry_manager) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < metadataChanges.Count; i++) { CkanModule module = metadataChanges[i]; sb.AppendLine(string.Format("- {0} {1}", module.identifier, module.version)); } if (user.RaiseYesNoDialog(string.Format(@"The following mods have had their metadata changed since last update: {0} You should reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", sb))) { ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, cache, new NullUser()); // New upstream metadata may break the consistency of already installed modules // e.g. if user installs modules A and B and then later up A is made to conflict with B // This is perfectly normal and shouldn't produce an error, therefore we skip enforcing // consistency. However, we will show the user any inconsistencies later on. // Do each changed module one at a time so a failure of one doesn't cause all the others to fail foreach (CkanModule mod in metadataChanges) { try { HashSet <string> possibleConfigOnlyDirs = null; installer.Upgrade( new CkanModule[] { mod }, new NetAsyncModulesDownloader(new NullUser(), cache), ref possibleConfigOnlyDirs, registry_manager, enforceConsistency: false, resolveRelationships: true ); } // Thrown when a dependency couldn't be satisfied catch (ModuleNotFoundKraken) { log.WarnFormat("Skipping installation of {0} due to relationship error.", mod.identifier); user.RaiseMessage("Skipping installation of {0} due to relationship error.", mod.identifier); } // Thrown when a conflicts relationship is violated catch (InconsistentKraken) { log.WarnFormat("Skipping installation of {0} due to relationship error.", mod.identifier); user.RaiseMessage("Skipping installation of {0} due to relationship error.", mod.identifier); } } } }
private void InstallMods(object sender, DoWorkEventArgs e) // this probably needs to be refactored { installCanceled = false; ClearLog(); var opts = (KeyValuePair <List <KeyValuePair <CkanModule, GUIModChangeType> >, RelationshipResolverOptions>)e.Argument; var installer = ModuleInstaller.Instance; // setup progress callback installer.onReportProgress += InstallModsReportProgress; // first we uninstall whatever the user wanted to plus the mods we want to update foreach (var change in opts.Key) { if (change.Value == GUIModChangeType.Remove) { SetDescription(String.Format("Uninstalling mod \"{0}\"", change.Key.name)); installer.UninstallList(change.Key.identifier); } else if (change.Value == GUIModChangeType.Update) { // TODO: Proper upgrades when ckan.dll supports them. installer.UninstallList(change.Key.identifier); } } toInstall = new HashSet <string>(); foreach (var change in opts.Key) { if (change.Value == GUIModChangeType.Install) { toInstall.Add(change.Key.identifier); } } var recommended = new Dictionary <string, List <string> >(); var suggested = new Dictionary <string, List <string> >(); foreach (var change in opts.Key) { if (change.Value == GUIModChangeType.Install) { if (change.Key.recommends != null) { foreach (RelationshipDescriptor mod in change.Key.recommends) { try { // if the mod is available for the current KSP version _and_ // the mod is not installed _and_ // the mod is not already in the install list if ( RegistryManager.Instance(KSPManager.CurrentInstance) .registry.LatestAvailable(mod.name.ToString(), KSPManager.CurrentInstance.Version()) != null && !RegistryManager.Instance(KSPManager.CurrentInstance).registry.IsInstalled(mod.name.ToString()) && !toInstall.Contains(mod.name.ToString())) { // add it to the list of recommended mods we display to the user if (recommended.ContainsKey(mod.name)) { recommended[mod.name].Add(change.Key.identifier); } else { recommended.Add(mod.name, new List <string> { change.Key.identifier }); } } } catch (Kraken) { } } } if (change.Key.suggests != null) { foreach (RelationshipDescriptor mod in change.Key.suggests) { try { if ( RegistryManager.Instance(KSPManager.CurrentInstance) .registry.LatestAvailable(mod.name.ToString(), KSPManager.CurrentInstance.Version()) != null && !RegistryManager.Instance(KSPManager.CurrentInstance).registry.IsInstalled(mod.name.ToString()) && !toInstall.Contains(mod.name.ToString())) { if (suggested.ContainsKey(mod.name)) { suggested[mod.name].Add(change.Key.identifier); } else { suggested.Add(mod.name, new List <string> { change.Key.identifier }); } } } catch (Kraken) { } } } } else if (change.Value == GUIModChangeType.Update) { // any mods for update we just put in the install list toInstall.Add(change.Key.identifier); } } if (recommended.Any()) { Util.Invoke(this, () => UpdateRecommendedDialog(recommended)); m_TabController.ShowTab("ChooseRecommendedModsTabPage", 3); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); } m_TabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); return; } m_TabController.RenameTab("WaitTabPage", "Installing mods"); m_TabController.ShowTab("WaitTabPage"); bool resolvedAllProvidedMods = false; while (!resolvedAllProvidedMods) { try { InstallList(toInstall, opts.Value); resolvedAllProvidedMods = true; } catch (TooManyModsProvideKraken tooManyProvides) { Util.Invoke(this, () => UpdateProvidedModsDialog(tooManyProvides)); m_TabController.ShowTab("ChooseProvidedModsTabPage", 3); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); m_TabController.HideTab("ChooseProvidedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); return; } m_TabController.ShowTab("WaitTabPage"); } } }
private void InstallMods(object sender, DoWorkEventArgs e) // this probably needs to be refactored { installCanceled = false; ClearLog(); var opts = (KeyValuePair <ModChanges, RelationshipResolverOptions>)e.Argument; IRegistryQuerier registry = RegistryManager.Instance(manager.CurrentInstance).registry; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, GUI.user); // setup progress callback toInstall = new HashSet <string>(); var toUninstall = new HashSet <string>(); var toUpgrade = new HashSet <string>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (ModChange change in opts.Key) { switch (change.ChangeType) { case GUIModChangeType.Remove: toUninstall.Add(change.Mod.Identifier); break; case GUIModChangeType.Update: toUpgrade.Add(change.Mod.Identifier); break; case GUIModChangeType.Install: toInstall.Add(change.Mod.Identifier); break; } } // Now work on satisifying dependencies. var recommended = new Dictionary <string, List <string> >(); var suggested = new Dictionary <string, List <string> >(); foreach (var change in opts.Key) { if (change.ChangeType == GUIModChangeType.Install) { AddMod(change.Mod.ToModule().recommends, recommended, change.Mod.Identifier, registry); AddMod(change.Mod.ToModule().suggests, suggested, change.Mod.Identifier, registry); } } ShowSelection(recommended); ShowSelection(suggested, true); tabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { tabController.HideTab("WaitTabPage"); tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. tabController.RenameTab("WaitTabPage", "Status log"); tabController.ShowTab("WaitTabPage"); tabController.SetTabLock(true); var downloader = new NetAsyncModulesDownloader(GUI.user); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; //Transaction is needed here to revert changes when an installation is cancelled //TODO: Cancellation should be handelt in the ModuleInstaller using (var transaction = CkanTransaction.CreateTransactionScope()) { //Set the result to false/failed in case we return e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); SetDescription("Uninstalling selected mods"); if (!WasSuccessful(() => installer.UninstallList(toUninstall))) { return; } if (installCanceled) { return; } SetDescription("Updating selected mods"); if (!WasSuccessful(() => installer.Upgrade(toUpgrade, downloader))) { return; } if (installCanceled) { return; } // TODO: We should be able to resolve all our provisioning conflicts // before we start installing anything. CKAN.SanityChecker can be used to // pre-check if our changes are going to be consistent. bool resolvedAllProvidedMods = false; while (!resolvedAllProvidedMods) { if (installCanceled) { e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } var ret = InstallList(toInstall, opts.Value, downloader); if (!ret) { // install failed for some reason, error message is already displayed to the user e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } resolvedAllProvidedMods = true; } if (!installCanceled) { transaction.Complete(); } } e.Result = new KeyValuePair <bool, ModChanges>(!installCanceled, opts.Key); }
private void _UpdateModsList(bool repo_updated, IEnumerable <ModChange> mc) { log.Info("Updating the mod list"); KspVersionCriteria versionCriteria = CurrentInstance.VersionCriteria(); IRegistryQuerier registry = RegistryManager.Instance(CurrentInstance).registry; var gui_mods = new HashSet <GUIMod>(); 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)) ); if (mc != null) { foreach (ModChange change in mc) { // Propagate IsInstallChecked and IsUpgradeChecked to the next generation gui_mods.FirstOrDefault( mod => mod.Identifier == change.Mod.Identifier )?.SetRequestedChange(change.ChangeType); } } var old_modules = mainModList.Modules.ToDictionary(m => m, m => m.IsIncompatible); if (repo_updated) { foreach (GUIMod gm in gui_mods) { bool oldIncompat; if (old_modules.TryGetValue(gm, out oldIncompat)) { // Found it; check if newly compatible if (!gm.IsIncompatible && oldIncompat) { gm.IsNew = true; } } else { // Newly indexed, show regardless of compatibility gm.IsNew = true; } } } else { //Copy the new mod flag from the old list. var old_new_mods = new HashSet <GUIMod>(old_modules.Keys.Where(m => m.IsNew)); foreach (var gui_mod in gui_mods.Where(m => old_new_mods.Contains(m))) { gui_mod.IsNew = true; } } // Update our mod listing mainModList.ConstructModList(gui_mods.ToList(), mc, configuration.HideEpochs, configuration.HideV); mainModList.Modules = new ReadOnlyCollection <GUIMod>( mainModList.full_list_of_mod_rows.Values.Select(row => row.Tag as GUIMod).ToList()); //TODO Consider using smart enumeration pattern so stuff like this is easier FilterToolButton.DropDownItems[0].Text = String.Format("Compatible ({0})", mainModList.CountModsByFilter(GUIModFilter.Compatible)); FilterToolButton.DropDownItems[1].Text = String.Format("Installed ({0})", mainModList.CountModsByFilter(GUIModFilter.Installed)); FilterToolButton.DropDownItems[2].Text = String.Format("Upgradeable ({0})", mainModList.CountModsByFilter(GUIModFilter.InstalledUpdateAvailable)); FilterToolButton.DropDownItems[3].Text = String.Format("Cached ({0})", mainModList.CountModsByFilter(GUIModFilter.Cached)); FilterToolButton.DropDownItems[4].Text = String.Format("Newly compatible ({0})", mainModList.CountModsByFilter(GUIModFilter.NewInRepository)); FilterToolButton.DropDownItems[5].Text = String.Format("Not installed ({0})", mainModList.CountModsByFilter(GUIModFilter.NotInstalled)); FilterToolButton.DropDownItems[6].Text = String.Format("Incompatible ({0})", mainModList.CountModsByFilter(GUIModFilter.Incompatible)); FilterToolButton.DropDownItems[7].Text = String.Format("All ({0})", mainModList.CountModsByFilter(GUIModFilter.All)); var has_any_updates = gui_mods.Any(mod => mod.HasUpdate); UpdateAllToolButton.Enabled = has_any_updates; UpdateFilters(this); UpdateTrayInfo(); }
private void _UpdateModsList(bool repo_updated, List <ModChange> mc) { log.Info("Updating the mod list"); KspVersionCriteria versionCriteria = CurrentInstance.VersionCriteria(); IRegistryQuerier registry = RegistryManager.Instance(CurrentInstance).registry; var gui_mods = new HashSet <GUIMod>(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 old_modules = new HashSet <GUIMod>(mainModList.Modules); if (repo_updated) { foreach (var gui_mod in gui_mods.Where(m => !old_modules.Contains(m))) { gui_mod.IsNew = true; } } else { //Copy the new mod flag from the old list. var old_new_mods = new HashSet <GUIMod>(old_modules.Where(m => m.IsNew)); foreach (var gui_mod in gui_mods.Where(m => old_new_mods.Contains(m))) { gui_mod.IsNew = true; } } // Update our mod listing. If we're doing a repo update, then we don't refresh // all (in case the user has selected changes they wish to apply). mainModList.ConstructModList(gui_mods.ToList(), mc, !repo_updated, configuration.HideEpochs); mainModList.Modules = new ReadOnlyCollection <GUIMod>( mainModList.full_list_of_mod_rows.Values.Select(row => row.Tag as GUIMod).ToList()); //TODO Consider using smart enumeration pattern so stuff like this is easier FilterToolButton.DropDownItems[0].Text = String.Format("Compatible ({0})", mainModList.CountModsByFilter(GUIModFilter.Compatible)); FilterToolButton.DropDownItems[1].Text = String.Format("Installed ({0})", mainModList.CountModsByFilter(GUIModFilter.Installed)); FilterToolButton.DropDownItems[2].Text = String.Format("Upgradeable ({0})", mainModList.CountModsByFilter(GUIModFilter.InstalledUpdateAvailable)); FilterToolButton.DropDownItems[3].Text = String.Format("Cached ({0})", mainModList.CountModsByFilter(GUIModFilter.Cached)); FilterToolButton.DropDownItems[4].Text = String.Format("New in repository ({0})", mainModList.CountModsByFilter(GUIModFilter.NewInRepository)); FilterToolButton.DropDownItems[5].Text = String.Format("Not installed ({0})", mainModList.CountModsByFilter(GUIModFilter.NotInstalled)); FilterToolButton.DropDownItems[6].Text = String.Format("Incompatible ({0})", mainModList.CountModsByFilter(GUIModFilter.Incompatible)); FilterToolButton.DropDownItems[7].Text = String.Format("All ({0})", mainModList.CountModsByFilter(GUIModFilter.All)); var has_any_updates = gui_mods.Any(mod => mod.HasUpdate); UpdateAllToolButton.Enabled = has_any_updates; UpdateFilters(this); }
protected override void OnLoad(EventArgs e) { Location = configuration.WindowLoc; Size = configuration.WindowSize; WindowState = configuration.IsWindowMaximised ? FormWindowState.Maximized : FormWindowState.Normal; try { splitContainer1.SplitterDistance = configuration.PanelPosition; } catch { // SplitContainer is mis-designed to throw exceptions // if the min/max limits are exceeded rather than simply obeying them. } ModInfoTabControl.ModMetaSplitPosition = configuration.ModInfoPosition; if (!configuration.CheckForUpdatesOnLaunchNoNag && AutoUpdate.CanUpdate) { log.Debug("Asking user if they wish for auto-updates"); if (new AskUserForAutoUpdatesDialog().ShowDialog() == DialogResult.OK) { configuration.CheckForUpdatesOnLaunch = true; } configuration.CheckForUpdatesOnLaunchNoNag = true; configuration.Save(); } bool autoUpdating = false; if (configuration.CheckForUpdatesOnLaunch && AutoUpdate.CanUpdate) { try { log.Info("Making auto-update call"); AutoUpdate.Instance.FetchLatestReleaseInfo(); var latest_version = AutoUpdate.Instance.latestUpdate.Version; var current_version = new ModuleVersion(Meta.GetVersion()); if (AutoUpdate.Instance.IsFetched() && latest_version.IsGreaterThan(current_version)) { log.Debug("Found higher ckan version"); var release_notes = AutoUpdate.Instance.latestUpdate.ReleaseNotes; var dialog = new NewUpdateDialog(latest_version.ToString(), release_notes); if (dialog.ShowDialog() == DialogResult.OK) { UpdateCKAN(); autoUpdating = true; } } } catch (Exception exception) { currentUser.RaiseError($"Error in auto-update:\n\t{exception.Message}"); log.Error("Error in auto-update", exception); } } CheckTrayState(); InitRefreshTimer(); m_UpdateRepoWorker = new BackgroundWorker { WorkerReportsProgress = false, WorkerSupportsCancellation = true }; m_UpdateRepoWorker.RunWorkerCompleted += PostUpdateRepo; m_UpdateRepoWorker.DoWork += UpdateRepo; installWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; installWorker.RunWorkerCompleted += PostInstallMods; installWorker.DoWork += InstallMods; var old_YesNoDialog = currentUser.displayYesNo; currentUser.displayYesNo = YesNoDialog; URLHandlers.RegisterURLHandler(configuration, currentUser); currentUser.displayYesNo = old_YesNoDialog; ApplyToolButton.Enabled = false; CurrentInstanceUpdated(); // We would like to refresh if we're configured to refresh on startup, // or if we have no currently available modules. bool repoUpdateNeeded = configuration.RefreshOnStartup || !RegistryManager.Instance(CurrentInstance).registry.HasAnyAvailable(); // If we're auto-updating the client then we shouldn't interfere with the progress tab if (!autoUpdating && repoUpdateNeeded) { UpdateRepo(); } Text = $"CKAN {Meta.GetVersion()} - KSP {CurrentInstance.Version()} -- {CurrentInstance.GameDir()}"; if (commandLineArgs.Length >= 2) { var identifier = commandLineArgs[1]; if (identifier.StartsWith("//")) { identifier = identifier.Substring(2); } else if (identifier.StartsWith("ckan://")) { identifier = identifier.Substring(7); } if (identifier.EndsWith("/")) { identifier = identifier.Substring(0, identifier.Length - 1); } log.Debug("Attempting to select mod from startup parameters"); FocusMod(identifier, true, true); ModList.Refresh(); log.Debug("Failed to select mod from startup parameters"); } var pluginsPath = Path.Combine(CurrentInstance.CkanDir(), "Plugins"); if (!Directory.Exists(pluginsPath)) { Directory.CreateDirectory(pluginsPath); } pluginController = new PluginController(pluginsPath); CurrentInstance.RebuildKSPSubDir(); // Initialize navigation. This should be called as late as // possible, once the UI is "settled" from its initial load. NavInit(); log.Info("GUI started"); base.OnLoad(e); }
public Main(string[] cmdlineArgs, GUIUser user, bool showConsole) { log.Info("Starting the GUI"); commandLineArgs = cmdlineArgs; currentUser = user; user.displayMessage = AddStatusMessage; user.displayError = ErrorDialog; controlFactory = new ControlFactory(); Instance = this; mainModList = new MainModList(source => UpdateFilters(this), TooManyModsProvide, user); // History is read-only until the UI is started. We switch // out of it at the end of OnLoad() when we call NavInit(). navHistory = new NavigationHistory <GUIMod> { IsReadOnly = true }; InitializeComponent(); // We need to initialize the error dialog first to display errors. errorDialog = controlFactory.CreateControl <ErrorDialog>(); // We want to check if our current instance is null first, // as it may have already been set by a command-line option. Manager = new KSPManager(user); if (CurrentInstance == null && manager.GetPreferredInstance() == null) { Hide(); var result = new ChooseKSPInstance().ShowDialog(); if (result == DialogResult.Cancel || result == DialogResult.Abort) { Application.Exit(); return; } } configuration = Configuration.LoadOrCreateConfiguration ( Path.Combine(CurrentInstance.CkanDir(), "GUIConfig.xml"), Repo.default_ckan_repo.ToString() ); // Check if there is any other instances already running. // This is not entirely necessary, but we can show a nicer error message this way. try { #pragma warning disable 219 var lockedReg = RegistryManager.Instance(CurrentInstance).registry; #pragma warning restore 219 } catch (RegistryInUseKraken kraken) { errorDialog.ShowErrorDialog(kraken.ToString()); return; } FilterToolButton.MouseHover += (sender, args) => FilterToolButton.ShowDropDown(); launchKSPToolStripMenuItem.MouseHover += (sender, args) => launchKSPToolStripMenuItem.ShowDropDown(); ApplyToolButton.MouseHover += (sender, args) => ApplyToolButton.ShowDropDown(); ModList.CurrentCellDirtyStateChanged += ModList_CurrentCellDirtyStateChanged; ModList.CellValueChanged += ModList_CellValueChanged; tabController = new TabController(MainTabControl); tabController.ShowTab("ManageModsTabPage"); RecreateDialogs(); if (!showConsole) { Util.HideConsoleWindow(); } // Disable the modinfo controls until a mod has been choosen. ModInfoTabControl.SelectedModule = null; // WinForms on Mac OS X has a nasty bug where the UI thread hogs the CPU, // making our download speeds really slow unless you move the mouse while // downloading. Yielding periodically addresses that. // https://bugzilla.novell.com/show_bug.cgi?id=663433 if (Platform.IsMac) { var timer = new Timer { Interval = 2 }; timer.Tick += (sender, e) => { Thread.Yield(); }; timer.Start(); } Application.Run(this); var registry = RegistryManager.Instance(Manager.CurrentInstance); registry?.Dispose(); }
protected override void OnLoad(EventArgs e) { if (configuration.WindowLoc.X == -1 && configuration.WindowLoc.Y == -1) { // Center on screen for first launch StartPosition = FormStartPosition.CenterScreen; } else if (Platform.IsMac) { // Make sure there's room at the top for the MacOSX menu bar Location = Util.ClampedLocationWithMargins( configuration.WindowLoc, configuration.WindowSize, new Size(0, 30), new Size(0, 0) ); } else { // Just make sure it's fully on screen Location = Util.ClampedLocation(configuration.WindowLoc, configuration.WindowSize); } Size = configuration.WindowSize; WindowState = configuration.IsWindowMaximised ? FormWindowState.Maximized : FormWindowState.Normal; #if (!ONI) if (!configuration.CheckForUpdatesOnLaunchNoNag && AutoUpdate.CanUpdate) { log.Debug("Asking user if they wish for auto-updates"); if (new AskUserForAutoUpdatesDialog().ShowDialog() == DialogResult.OK) { configuration.CheckForUpdatesOnLaunch = true; } configuration.CheckForUpdatesOnLaunchNoNag = true; configuration.Save(); } #else configuration.CheckForUpdatesOnLaunch = false; configuration.CheckForUpdatesOnLaunchNoNag = false; configuration.Save(); #endif bool autoUpdating = false; if (configuration.CheckForUpdatesOnLaunch && AutoUpdate.CanUpdate) { try { log.Info("Making auto-update call"); AutoUpdate.Instance.FetchLatestReleaseInfo(); var latest_version = AutoUpdate.Instance.latestUpdate.Version; var current_version = new ModuleVersion(Meta.GetVersion()); if (AutoUpdate.Instance.IsFetched() && latest_version.IsGreaterThan(current_version)) { log.Debug("Found higher ckan version"); var release_notes = AutoUpdate.Instance.latestUpdate.ReleaseNotes; var dialog = new NewUpdateDialog(latest_version.ToString(), release_notes); if (dialog.ShowDialog() == DialogResult.OK) { UpdateCKAN(); autoUpdating = true; } } } catch (Exception exception) { currentUser.RaiseError($"Error in auto-update:\n\t{exception.Message}"); log.Error("Error in auto-update", exception); } } CheckTrayState(); InitRefreshTimer(); m_UpdateRepoWorker = new BackgroundWorker { WorkerReportsProgress = false, WorkerSupportsCancellation = true }; m_UpdateRepoWorker.RunWorkerCompleted += PostUpdateRepo; m_UpdateRepoWorker.DoWork += UpdateRepo; installWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; installWorker.RunWorkerCompleted += PostInstallMods; installWorker.DoWork += InstallMods; #if (!ONI) URLHandlers.RegisterURLHandler(configuration, currentUser); #endif ApplyToolButton.Enabled = false; CurrentInstanceUpdated(); // We would like to refresh if we're configured to refresh on startup, // or if we have no currently available modules. bool repoUpdateNeeded = configuration.RefreshOnStartup || !RegistryManager.Instance(CurrentInstance).registry.HasAnyAvailable(); // If we're auto-updating the client then we shouldn't interfere with the progress tab if (!autoUpdating && repoUpdateNeeded) { UpdateRepo(); } Text = $"CKAN {Meta.GetVersion()} - {GameConfig.Constants.GameNameShort} {CurrentInstance.Version()} -- {CurrentInstance.GameDir()}"; if (commandLineArgs.Length >= 2) { var identifier = commandLineArgs[1]; if (identifier.StartsWith("//")) { identifier = identifier.Substring(2); } else if (identifier.StartsWith("ckan://")) { identifier = identifier.Substring(7); } if (identifier.EndsWith("/")) { identifier = identifier.Substring(0, identifier.Length - 1); } log.Debug("Attempting to select mod from startup parameters"); FocusMod(identifier, true, true); ModList.Refresh(); log.Debug("Failed to select mod from startup parameters"); } var pluginsPath = Path.Combine(CurrentInstance.CkanDir(), "Plugins"); if (!Directory.Exists(pluginsPath)) { Directory.CreateDirectory(pluginsPath); } pluginController = new PluginController(pluginsPath); CurrentInstance.RebuildKSPSubDir(); // Initialize navigation. This should be called as late as // possible, once the UI is "settled" from its initial load. NavInit(); log.Info("GUI started"); base.OnLoad(e); }
private void UpdateRecommendedDialog(Dictionary <string, List <string> > mods, bool suggested = false) { if (!suggested) { RecommendedDialogLabel.Text = "The following modules have been recommended by one or more of the chosen modules:"; RecommendedModsListView.Columns[1].Text = "Recommended by:"; } else { RecommendedDialogLabel.Text = "The following modules have been suggested by one or more of the chosen modules:"; RecommendedModsListView.Columns[1].Text = "Suggested by:"; } RecommendedModsListView.Items.Clear(); foreach (var pair in mods) { CkanModule module; try { module = RegistryManager.Instance(manager.CurrentInstance).registry.LatestAvailable(pair.Key, CurrentInstance.Version()); } catch { continue; } if (module == null) { continue; } ListViewItem item = new ListViewItem { Tag = module, Checked = !suggested, Text = pair.Key }; ListViewItem.ListViewSubItem recommendedBy = new ListViewItem.ListViewSubItem(); string recommendedByString = ""; bool first = true; foreach (string mod in pair.Value) { if (!first) { recommendedByString += ", "; } else { first = false; } recommendedByString += mod; } recommendedBy.Text = recommendedByString; item.SubItems.Add(recommendedBy); ListViewItem.ListViewSubItem description = new ListViewItem.ListViewSubItem { Text = module.@abstract }; item.SubItems.Add(description); RecommendedModsListView.Items.Add(item); } }
// this probably needs to be refactored private void InstallMods(object sender, DoWorkEventArgs e) { installCanceled = false; ClearLog(); var opts = (KeyValuePair <ModChanges, RelationshipResolverOptions>)e.Argument; IRegistryQuerier registry = RegistryManager.Instance(manager.CurrentInstance).registry; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, Manager.Cache, GUI.user); // Avoid accumulating multiple event handlers installer.onReportModInstalled -= OnModInstalled; installer.onReportModInstalled += OnModInstalled; // setup progress callback // this will be the final list of mods we want to install HashSet <CkanModule> toInstall = new HashSet <CkanModule>(); var toUninstall = new HashSet <string>(); var toUpgrade = new HashSet <string>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (ModChange change in opts.Key) { switch (change.ChangeType) { case GUIModChangeType.Remove: toUninstall.Add(change.Mod.identifier); break; case GUIModChangeType.Update: toUpgrade.Add(change.Mod.identifier); break; case GUIModChangeType.Install: toInstall.Add(change.Mod); break; case GUIModChangeType.Replace: ModuleReplacement repl = registry.GetReplacement(change.Mod, CurrentInstance.VersionCriteria()); if (repl != null) { toUninstall.Add(repl.ToReplace.identifier); toInstall.Add(repl.ReplaceWith); } break; } } // Prompt for recommendations and suggestions, if any var recRows = getRecSugRows( opts.Key.Where(ch => ch.ChangeType == GUIModChangeType.Install) .Select(ch => ch.Mod), registry, toInstall ); if (recRows.Any()) { ShowRecSugDialog(recRows, toInstall); } tabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. tabController.RenameTab("WaitTabPage", Properties.Resources.MainInstallWaitTitle); ShowWaitDialog(); tabController.SetTabLock(true); IDownloader downloader = new NetAsyncModulesDownloader(GUI.user, Manager.Cache); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; // checks if all actions were successfull bool processSuccessful = false; bool resolvedAllProvidedMods = false; // uninstall/installs/upgrades until every list is empty // if the queue is NOT empty, resolvedAllProvidedMods is set to false until the action is done while (!resolvedAllProvidedMods) { try { e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); if (toUninstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.UninstallList(toUninstall, false, toInstall.Select(m => m.identifier)); processSuccessful = true; } } if (toUpgrade.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.Upgrade(toUpgrade, downloader); processSuccessful = true; } } if (toInstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.InstallList(toInstall, opts.Value, downloader, false); processSuccessful = true; } } e.Result = new KeyValuePair <bool, ModChanges>(processSuccessful, opts.Key); if (installCanceled) { return; } resolvedAllProvidedMods = true; } catch (TooManyModsProvideKraken k) { // Prompt user to choose which mod to use CkanModule chosen = TooManyModsProvideCore(k).Result; // Close the selection prompt Util.Invoke(this, () => { tabController.ShowTab("WaitTabPage"); tabController.HideTab("ChooseProvidedModsTabPage"); }); if (chosen != null) { // User picked a mod, queue it up for installation toInstall.Add(chosen); // DON'T return so we can loop around and try the above InstallList call again } else { // User cancelled, get out tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } } catch (DependencyNotSatisfiedKraken ex) { GUI.user.RaiseMessage(Properties.Resources.MainInstallDepNotSatisfied, ex.parent, ex.module); return; } catch (ModuleNotFoundKraken ex) { GUI.user.RaiseMessage(Properties.Resources.MainInstallNotFound, ex.module); return; } catch (BadMetadataKraken ex) { GUI.user.RaiseMessage(Properties.Resources.MainInstallBadMetadata, ex.module, ex.Message); return; } catch (FileExistsKraken ex) { if (ex.owningModule != null) { GUI.user.RaiseMessage( Properties.Resources.MainInstallFileExists, ex.filename, ex.installingModule, ex.owningModule, Meta.GetVersion() ); } else { GUI.user.RaiseMessage( Properties.Resources.MainInstallUnownedFileExists, ex.installingModule, ex.filename ); } GUI.user.RaiseMessage(Properties.Resources.MainInstallGameDataReverted); return; } catch (InconsistentKraken ex) { // The prettiest Kraken formats itself for us. GUI.user.RaiseMessage(ex.InconsistenciesPretty); return; } catch (CancelledActionKraken) { return; } catch (MissingCertificateKraken kraken) { // Another very pretty kraken. GUI.user.RaiseMessage(kraken.ToString()); return; } catch (DownloadThrottledKraken kraken) { string msg = kraken.ToString(); GUI.user.RaiseMessage(msg); if (YesNoDialog(string.Format(Properties.Resources.MainInstallOpenSettingsPrompt, msg), Properties.Resources.MainInstallOpenSettings, Properties.Resources.MainInstallNo)) { // Launch the URL describing this host's throttling practices, if any if (kraken.infoUrl != null) { Process.Start(new ProcessStartInfo() { UseShellExecute = true, FileName = kraken.infoUrl.ToString() }); } // Now pretend they clicked the menu option for the settings Enabled = false; settingsDialog.ShowDialog(); Enabled = true; } return; } catch (ModuleDownloadErrorsKraken kraken) { GUI.user.RaiseMessage(kraken.ToString()); GUI.user.RaiseError(kraken.ToString()); return; } catch (DirectoryNotFoundKraken kraken) { GUI.user.RaiseMessage("\r\n{0}", kraken.Message); return; } catch (DllNotFoundException) { if (GUI.user.RaiseYesNoDialog(Properties.Resources.MainInstallLibCurlMissing)) { Process.Start(new ProcessStartInfo() { UseShellExecute = true, FileName = "https://github.com/KSP-CKAN/CKAN/wiki/libcurl" }); } throw; } } }
private void InstallMods(object sender, DoWorkEventArgs e) // this probably needs to be refactored { installCanceled = false; ClearLog(); var opts = (KeyValuePair <List <KeyValuePair <CkanModule, GUIModChangeType> >, RelationshipResolverOptions>)e.Argument; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, GUI.user); // setup progress callback toInstall = new HashSet <string>(); var toUninstall = new HashSet <string>(); var toUpgrade = new HashSet <string>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (KeyValuePair <CkanModule, GUIModChangeType> change in opts.Key) { switch (change.Value) { case GUIModChangeType.Remove: toUninstall.Add(change.Key.identifier); break; case GUIModChangeType.Update: toUpgrade.Add(change.Key.identifier); break; case GUIModChangeType.Install: toInstall.Add(change.Key.identifier); break; } } // Now work on satisifying dependencies. var recommended = new Dictionary <string, List <string> >(); var suggested = new Dictionary <string, List <string> >(); foreach (var change in opts.Key) { if (change.Value == GUIModChangeType.Install) { if (change.Key.recommends != null) { foreach (RelationshipDescriptor mod in change.Key.recommends) { try { // if the mod is available for the current KSP version _and_ // the mod is not installed _and_ // the mod is not already in the install list if ( RegistryManager.Instance(manager.CurrentInstance) .registry.LatestAvailable(mod.name, manager.CurrentInstance.Version()) != null && !RegistryManager.Instance(manager.CurrentInstance) .registry.IsInstalled(mod.name) && !toInstall.Contains(mod.name)) { // add it to the list of recommended mods we display to the user if (recommended.ContainsKey(mod.name)) { recommended[mod.name].Add(change.Key.identifier); } else { recommended.Add(mod.name, new List <string> { change.Key.identifier }); } } } // XXX - Don't ignore all krakens! Those things are important! catch (Kraken) { } } } if (change.Key.suggests != null) { foreach (RelationshipDescriptor mod in change.Key.suggests) { try { if ( RegistryManager.Instance(manager.CurrentInstance).registry.LatestAvailable(mod.name, manager.CurrentInstance.Version()) != null && !RegistryManager.Instance(manager.CurrentInstance).registry.IsInstalled(mod.name) && !toInstall.Contains(mod.name)) { if (suggested.ContainsKey(mod.name)) { suggested[mod.name].Add(change.Key.identifier); } else { suggested.Add(mod.name, new List <string> { change.Key.identifier }); } } } // XXX - Don't ignore all krakens! Those things are important! catch (Kraken) { } } } } } // If we're going to install something anyway, then don't list it in the // recommended list, since they can't de-select it anyway. foreach (var item in toInstall) { recommended.Remove(item); } // If there are any mods that would be recommended, prompt the user to make // selections. if (recommended.Any()) { Util.Invoke(this, () => UpdateRecommendedDialog(recommended)); m_TabController.ShowTab("ChooseRecommendedModsTabPage", 3); m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose recommended mods"); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); } m_TabController.HideTab("ChooseRecommendedModsTabPage"); // And now on to suggestions. Again, we don't show anything that's scheduled to // be installed on our suggest list. foreach (var item in toInstall) { suggested.Remove(item); } if (suggested.Any()) { Util.Invoke(this, () => UpdateRecommendedDialog(suggested, true)); m_TabController.ShowTab("ChooseRecommendedModsTabPage", 3); m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose suggested mods"); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); } m_TabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(false, opts.Key); return; } // Now let's make all our changes. m_TabController.RenameTab("WaitTabPage", "Installing mods"); m_TabController.ShowTab("WaitTabPage"); m_TabController.SetTabLock(true); using (var transaction = new CkanTransaction()) { var downloader = new NetAsyncDownloader(GUI.user); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; SetDescription("Uninstalling selected mods"); installer.UninstallList(toUninstall); if (installCanceled) { return; } SetDescription("Updating selected mods"); installer.Upgrade(toUpgrade, downloader); // TODO: We should be able to resolve all our provisioning conflicts // before we start installing anything. CKAN.SanityChecker can be used to // pre-check if our changes are going to be consistent. bool resolvedAllProvidedMods = false; while (!resolvedAllProvidedMods) { if (installCanceled) { e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(false, opts.Key); return; } try { var ret = InstallList(toInstall, opts.Value, downloader); if (!ret) { // install failed for some reason, error message is already displayed to the user e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(false, opts.Key); return; } resolvedAllProvidedMods = true; } catch (TooManyModsProvideKraken tooManyProvides) { Util.Invoke(this, () => UpdateProvidedModsDialog(tooManyProvides)); m_TabController.ShowTab("ChooseProvidedModsTabPage", 3); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); m_TabController.HideTab("ChooseProvidedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(false, opts.Key); return; } m_TabController.ShowTab("WaitTabPage"); } } if (!installCanceled) { transaction.Complete(); } } e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(true, opts.Key); }
private void InstallMods(object sender, DoWorkEventArgs e) // this probably needs to be refactored { installCanceled = false; ClearLog(); var opts = (KeyValuePair <ModChanges, RelationshipResolverOptions>)e.Argument; IRegistryQuerier registry = RegistryManager.Instance(manager.CurrentInstance).registry; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, Manager.Cache, GUI.user); // Avoid accumulating multiple event handlers installer.onReportModInstalled -= OnModInstalled; installer.onReportModInstalled += OnModInstalled; // setup progress callback toInstall = new HashSet <CkanModule>(); var toUninstall = new HashSet <string>(); var toUpgrade = new HashSet <string>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (ModChange change in opts.Key) { switch (change.ChangeType) { case GUIModChangeType.Remove: toUninstall.Add(change.Mod.Identifier); break; case GUIModChangeType.Update: toUpgrade.Add(change.Mod.Identifier); break; case GUIModChangeType.Install: toInstall.Add(change.Mod.ToModule()); break; } } // Now work on satisifying dependencies. var recommended = new Dictionary <CkanModule, List <string> >(); var suggested = new Dictionary <CkanModule, List <string> >(); foreach (var change in opts.Key) { if (change.ChangeType == GUIModChangeType.Install) { AddMod(change.Mod.ToModule().recommends, recommended, change.Mod.Identifier, registry); AddMod(change.Mod.ToModule().suggests, suggested, change.Mod.Identifier, registry); } } ShowSelection(recommended); ShowSelection(suggested, true); tabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. tabController.RenameTab("WaitTabPage", "Status log"); ShowWaitDialog(); tabController.SetTabLock(true); IDownloader downloader = new NetAsyncModulesDownloader(GUI.user); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; bool resolvedAllProvidedMods = false; while (!resolvedAllProvidedMods) { try { e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); if (!installCanceled && toUninstall.Count > 0) { installer.UninstallList(toUninstall); } if (!installCanceled && toUpgrade.Count > 0) { installer.Upgrade(toUpgrade, downloader); } if (!installCanceled && toInstall.Count > 0) { installer.InstallList(toInstall, opts.Value, downloader); } e.Result = new KeyValuePair <bool, ModChanges>(!installCanceled, opts.Key); if (installCanceled) { return; } resolvedAllProvidedMods = true; } catch (DependencyNotSatisfiedKraken ex) { GUI.user.RaiseMessage( "{0} requires {1} but it is not listed in the index, or not available for your version of KSP.", ex.parent, ex.module); return; } catch (ModuleNotFoundKraken ex) { GUI.user.RaiseMessage( "Module {0} required but it is not listed in the index, or not available for your version of KSP.", ex.module); return; } catch (BadMetadataKraken ex) { GUI.user.RaiseMessage("Bad metadata detected for module {0}: {1}", ex.module, ex.Message); return; } catch (FileExistsKraken ex) { if (ex.owningModule != null) { GUI.user.RaiseMessage( "\r\nOh no! We tried to overwrite a file owned by another mod!\r\n" + "Please try a `ckan update` and try again.\r\n\r\n" + "If this problem re-occurs, then it maybe a packaging bug.\r\n" + "Please report it at:\r\n\r\n" + "https://github.com/KSP-CKAN/NetKAN/issues/new\r\n\r\n" + "Please including the following information in your report:\r\n\r\n" + "File : {0}\r\n" + "Installing Mod : {1}\r\n" + "Owning Mod : {2}\r\n" + "CKAN Version : {3}\r\n", ex.filename, ex.installingModule, ex.owningModule, Meta.GetVersion() ); } else { GUI.user.RaiseMessage( "\r\n\r\nOh no!\r\n\r\n" + "It looks like you're trying to install a mod which is already installed,\r\n" + "or which conflicts with another mod which is already installed.\r\n\r\n" + "As a safety feature, the CKAN will *never* overwrite or alter a file\r\n" + "that it did not install itself.\r\n\r\n" + "If you wish to install {0} via the CKAN,\r\n" + "then please manually uninstall the mod which owns:\r\n\r\n" + "{1}\r\n\r\n" + "and try again.\r\n", ex.installingModule, ex.filename ); } GUI.user.RaiseMessage("Your GameData has been returned to its original state.\r\n"); return; } catch (InconsistentKraken ex) { // The prettiest Kraken formats itself for us. GUI.user.RaiseMessage(ex.InconsistenciesPretty); return; } catch (CancelledActionKraken) { return; } catch (MissingCertificateKraken kraken) { // Another very pretty kraken. GUI.user.RaiseMessage(kraken.ToString()); return; } catch (DownloadThrottledKraken kraken) { string msg = kraken.ToString(); GUI.user.RaiseMessage(msg); if (YesNoDialog($"{msg}\r\n\r\nOpen settings now?")) { // Launch the URL describing this host's throttling practices, if any if (kraken.infoUrl != null) { Process.Start(new ProcessStartInfo() { UseShellExecute = true, FileName = kraken.infoUrl.ToString() }); } // Now pretend they clicked the menu option for the settings Enabled = false; settingsDialog.ShowDialog(); Enabled = true; } return; } catch (ModuleDownloadErrorsKraken kraken) { GUI.user.RaiseMessage(kraken.ToString()); GUI.user.RaiseError(kraken.ToString()); return; } catch (DirectoryNotFoundKraken kraken) { GUI.user.RaiseMessage("\r\n{0}", kraken.Message); return; } catch (DllNotFoundException) { if (GUI.user.RaiseYesNoDialog("libcurl installation not found. Open wiki page for help?")) { Process.Start(new ProcessStartInfo() { UseShellExecute = true, FileName = "https://github.com/KSP-CKAN/CKAN/wiki/libcurl" }); } throw; } } }
private static int Update(RegistryManager registry_manager, KSP ksp, IUser user, Boolean clear = true, Uri repo = null) { // Use our default repo, unless we've been told otherwise. if (repo == null) { repo = default_ckan_repo; } UpdateRegistry(repo, registry_manager.registry, ksp, user, clear); // Save our changes! registry_manager.Save(enforce_consistency: false); ShowUserInconsistencies(registry_manager.registry, user); // Return how many we got! return registry_manager.registry.Available(ksp.VersionCriteria()).Count; }
// this probably needs to be refactored private void InstallMods(object sender, DoWorkEventArgs e) { installCanceled = false; Wait.ClearLog(); var opts = (KeyValuePair <ModChanges, RelationshipResolverOptions>)e.Argument; RegistryManager registry_manager = RegistryManager.Instance(manager.CurrentInstance); Registry registry = registry_manager.registry; ModuleInstaller installer = new ModuleInstaller(CurrentInstance, Manager.Cache, currentUser); // Avoid accumulating multiple event handlers installer.onReportModInstalled -= OnModInstalled; installer.onReportModInstalled += OnModInstalled; // setup progress callback // this will be the final list of mods we want to install HashSet <CkanModule> toInstall = new HashSet <CkanModule>(); var toUninstall = new HashSet <CkanModule>(); var toUpgrade = new HashSet <CkanModule>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (ModChange change in opts.Key) { switch (change.ChangeType) { case GUIModChangeType.Remove: toUninstall.Add(change.Mod); break; case GUIModChangeType.Update: toUpgrade.Add(change is ModUpgrade mu ? mu.targetMod : change.Mod); break; case GUIModChangeType.Install: toInstall.Add(change.Mod); break; case GUIModChangeType.Replace: ModuleReplacement repl = registry.GetReplacement(change.Mod, CurrentInstance.VersionCriteria()); if (repl != null) { toUninstall.Add(repl.ToReplace); toInstall.Add(repl.ReplaceWith); } break; } } // Prompt for recommendations and suggestions, if any if (installer.FindRecommendations( opts.Key.Where(ch => ch.ChangeType == GUIModChangeType.Install) .Select(ch => ch.Mod) .ToHashSet(), toInstall, registry, out Dictionary <CkanModule, Tuple <bool, List <string> > > recommendations, out Dictionary <CkanModule, List <string> > suggestions, out Dictionary <CkanModule, HashSet <string> > supporters )) { tabController.ShowTab("ChooseRecommendedModsTabPage", 3); ChooseRecommendedMods.LoadRecommendations( registry, toInstall, toUninstall, CurrentInstance.VersionCriteria(), Manager.Cache, recommendations, suggestions, supporters); tabController.SetTabLock(true); var result = ChooseRecommendedMods.Wait(); if (result == null) { installCanceled = true; } else { toInstall.UnionWith(result); } tabController.SetTabLock(false); tabController.HideTab("ChooseRecommendedModsTabPage"); } if (installCanceled) { Util.Invoke(this, () => Enabled = true); Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. Util.Invoke(this, () => { // Need to be on the GUI thread to get the translated string tabController.RenameTab("WaitTabPage", Properties.Resources.MainInstallWaitTitle); }); ShowWaitDialog(); tabController.SetTabLock(true); IDownloader downloader = new NetAsyncModulesDownloader(currentUser, Manager.Cache); downloader.Progress += Wait.SetModuleProgress; downloader.AllComplete += Wait.DownloadsComplete; cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; HashSet <string> possibleConfigOnlyDirs = null; // checks if all actions were successfull bool processSuccessful = false; bool resolvedAllProvidedMods = false; // uninstall/installs/upgrades until every list is empty // if the queue is NOT empty, resolvedAllProvidedMods is set to false until the action is done while (!resolvedAllProvidedMods) { try { e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); if (toUninstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.UninstallList(toUninstall.Select(m => m.identifier), ref possibleConfigOnlyDirs, registry_manager, false, toInstall); toUninstall.Clear(); processSuccessful = true; } } if (toInstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.InstallList(toInstall, opts.Value, registry_manager, ref possibleConfigOnlyDirs, downloader, false); toInstall.Clear(); processSuccessful = true; } } if (toUpgrade.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.Upgrade(toUpgrade, downloader, ref possibleConfigOnlyDirs, registry_manager, true, true, false); toUpgrade.Clear(); processSuccessful = true; } } HandlePossibleConfigOnlyDirs(registry, possibleConfigOnlyDirs); e.Result = new KeyValuePair <bool, ModChanges>(processSuccessful, opts.Key); if (installCanceled) { return; } resolvedAllProvidedMods = true; } catch (TooManyModsProvideKraken k) { // Prompt user to choose which mod to use tabController.ShowTab("ChooseProvidedModsTabPage", 3); ChooseProvidedMods.LoadProviders(k.requested, k.modules, Manager.Cache); tabController.SetTabLock(true); CkanModule chosen = ChooseProvidedMods.Wait(); // Close the selection prompt tabController.SetTabLock(false); tabController.HideTab("ChooseProvidedModsTabPage"); if (chosen != null) { // User picked a mod, queue it up for installation toInstall.Add(chosen); // DON'T return so we can loop around and try the above InstallList call again tabController.ShowTab("WaitTabPage"); } else { // User cancelled, get out tabController.ShowTab("ManageModsTabPage"); Util.Invoke(this, () => Enabled = true); Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } } } }
/// <summary> /// React to switching to a new game instance /// </summary> /// <param name="allowRepoUpdate">true if a repo update is allowed if needed (e.g. on initial load), false otherwise</param> private void CurrentInstanceUpdated(bool allowRepoUpdate) { Util.Invoke(this, () => { Text = $"CKAN {Meta.GetVersion()} - KSP {CurrentInstance.Version()} -- {CurrentInstance.GameDir().Replace('/', Path.DirectorySeparatorChar)}"; StatusInstanceLabel.Text = string.Format( Properties.Resources.StatusInstanceLabelText, CurrentInstance.Name, CurrentInstance.Version()?.ToString() ); }); configuration = GUIConfiguration.LoadOrCreateConfiguration( Path.Combine(CurrentInstance.CkanDir(), "GUIConfig.xml") ); if (CurrentInstance.CompatibleVersionsAreFromDifferentKsp) { new CompatibleKspVersionsDialog(CurrentInstance, !actuallyVisible) .ShowDialog(); } (RegistryManager.Instance(CurrentInstance).registry as Registry) ?.BuildTagIndex(ManageMods.mainModList.ModuleTags); bool repoUpdateNeeded = configuration.RefreshOnStartup || !RegistryManager.Instance(CurrentInstance).registry.HasAnyAvailable(); if (allowRepoUpdate && repoUpdateNeeded) { // Update the filters after UpdateRepo() completed. // Since this happens with a backgroundworker, Filter() is added as callback for RunWorkerCompleted. // Remove it again after it ran, else it stays there and is added again and again. void filterUpdate(object sender, RunWorkerCompletedEventArgs e) { ManageMods.Filter( (GUIModFilter)configuration.ActiveFilter, ManageMods.mainModList.ModuleTags.Tags.GetOrDefault(configuration.TagFilter), ManageMods.mainModList.ModuleLabels.LabelsFor(CurrentInstance.Name) .FirstOrDefault(l => l.Name == configuration.CustomLabelFilter) ); m_UpdateRepoWorker.RunWorkerCompleted -= filterUpdate; } m_UpdateRepoWorker.RunWorkerCompleted += filterUpdate; ManageMods.ModGrid.Rows.Clear(); UpdateRepo(); } else { ManageMods.UpdateModsList(); ManageMods.Filter( (GUIModFilter)configuration.ActiveFilter, ManageMods.mainModList.ModuleTags.Tags.GetOrDefault(configuration.TagFilter), ManageMods.mainModList.ModuleLabels.LabelsFor(CurrentInstance.Name) .FirstOrDefault(l => l.Name == configuration.CustomLabelFilter) ); } ManageMods.InstanceUpdated(CurrentInstance); }
private void _UpdateModsList(bool repo_updated) { log.Debug("Updating the mod list"); KSPVersion version = CurrentInstance.Version(); IRegistryQuerier registry = RegistryManager.Instance(CurrentInstance).registry; var gui_mods = new HashSet <GUIMod>(registry.Available(version) .Select(m => new GUIMod(m, registry, version))); gui_mods.UnionWith(registry.Incompatible(version) .Select(m => new GUIMod(m, registry, version))); var installed = registry.InstalledModules .Select(m => new GUIMod(m.Module, registry, version)); //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 old_modules = new HashSet <GUIMod>(mainModList.Modules); if (repo_updated) { foreach (var gui_mod in gui_mods.Where(m => !old_modules.Contains(m))) { gui_mod.IsNew = true; } } else { //Copy the new mod flag from the old list. var old_new_mods = new HashSet <GUIMod>(old_modules.Where(m => m.IsNew)); foreach (var gui_mod in gui_mods.Where(m => old_new_mods.Contains(m))) { gui_mod.IsNew = true; } } mainModList.Modules = new ReadOnlyCollection <GUIMod>(gui_mods.ToList()); mainModList.ConstructModList(mainModList.Modules); //TODO Consider using smart enum patten so stuff like this is easier FilterToolButton.DropDownItems[0].Text = String.Format("Compatible ({0})", mainModList.CountModsByFilter(GUIModFilter.Compatible)); FilterToolButton.DropDownItems[1].Text = String.Format("Installed ({0})", mainModList.CountModsByFilter(GUIModFilter.Installed)); FilterToolButton.DropDownItems[2].Text = String.Format("Upgradeable ({0})", mainModList.CountModsByFilter(GUIModFilter.InstalledUpdateAvailable)); FilterToolButton.DropDownItems[3].Text = String.Format("New in repository ({0})", mainModList.CountModsByFilter(GUIModFilter.NewInRepository)); FilterToolButton.DropDownItems[4].Text = String.Format("Not installed ({0})", mainModList.CountModsByFilter(GUIModFilter.NotInstalled)); FilterToolButton.DropDownItems[5].Text = String.Format("Incompatible ({0})", mainModList.CountModsByFilter(GUIModFilter.Incompatible)); FilterToolButton.DropDownItems[6].Text = String.Format("All ({0})", mainModList.CountModsByFilter(GUIModFilter.All)); var has_any_updates = gui_mods.Any(mod => mod.HasUpdate); UpdateAllToolButton.Enabled = has_any_updates; UpdateFilters(this); }
public Main(string[] cmdlineArgs, KSPManager mgr, bool showConsole) { log.Info("Starting the GUI"); commandLineArgs = cmdlineArgs; Configuration.IConfiguration mainConfig = ServiceLocator.Container.Resolve <Configuration.IConfiguration>(); // If the language is not set yet in the config, try to save the current language. // If it isn't supported, it'll still be null afterwards. Doesn't matter, .NET handles the resource selection. // Once the user chooses a language in the settings, the string will be no longer null, and we can change // CKAN's language here before any GUI components are initialized. if (string.IsNullOrEmpty(mainConfig.Language)) { string runtimeLanguage = Thread.CurrentThread.CurrentUICulture.IetfLanguageTag; mainConfig.Language = runtimeLanguage; } else { Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(mainConfig.Language); } InitializeComponent(); Instance = this; currentUser = new GUIUser(this, this.Wait); manager = mgr ?? new KSPManager(currentUser); controlFactory = new ControlFactory(); // React when the user clicks a tag or filter link in mod info ModInfo.OnChangeFilter += ManageMods.Filter; // Replace mono's broken, ugly toolstrip renderer if (Platform.IsMono) { menuStrip1.Renderer = new FlatToolStripRenderer(); fileToolStripMenuItem.DropDown.Renderer = new FlatToolStripRenderer(); settingsToolStripMenuItem.DropDown.Renderer = new FlatToolStripRenderer(); helpToolStripMenuItem.DropDown.Renderer = new FlatToolStripRenderer(); minimizedContextMenuStrip.Renderer = new FlatToolStripRenderer(); } // Initialize all user interaction dialogs. RecreateDialogs(); // We want to check if our current instance is null first, // as it may have already been set by a command-line option. if (CurrentInstance == null && manager.GetPreferredInstance() == null) { Hide(); var result = new ManageKspInstancesDialog(!actuallyVisible, currentUser).ShowDialog(); if (result == DialogResult.Cancel || result == DialogResult.Abort) { Application.Exit(); return; } } configuration = GUIConfiguration.LoadOrCreateConfiguration ( Path.Combine(CurrentInstance.CkanDir(), "GUIConfig.xml") ); // Check if there is any other instances already running. // This is not entirely necessary, but we can show a nicer error message this way. try { #pragma warning disable 219 var lockedReg = RegistryManager.Instance(CurrentInstance).registry; #pragma warning restore 219 } catch (RegistryInUseKraken kraken) { errorDialog.ShowErrorDialog(kraken.ToString()); return; } tabController = new TabController(MainTabControl); tabController.ShowTab("ManageModsTabPage"); if (!showConsole) { Util.HideConsoleWindow(); } // Disable the modinfo controls until a mod has been choosen. This has an effect if the modlist is empty. ActiveModInfo = null; // WinForms on Mac OS X has a nasty bug where the UI thread hogs the CPU, // making our download speeds really slow unless you move the mouse while // downloading. Yielding periodically addresses that. // https://bugzilla.novell.com/show_bug.cgi?id=663433 if (Platform.IsMac) { var timer = new Timer { Interval = 2 }; timer.Tick += (sender, e) => { Thread.Yield(); }; timer.Start(); } // Set the window name and class for X11 if (Platform.IsX11) { HandleCreated += (sender, e) => X11.SetWMClass("CKAN", "CKAN", Handle); } Application.Run(this); var registry = RegistryManager.Instance(Manager.CurrentInstance); registry?.Dispose(); }
private void UpdateRecommendedDialog(Dictionary <string, List <string> > mods, bool suggested = false) { if (!suggested) { RecommendedDialogLabel.Text = "The following modules have been recommended by one or more of the chosen modules:"; RecommendedModsListView.Columns[1].Text = "Recommended by:"; RecommendedModsToggleCheckbox.Text = "(De-)select all recommended mods."; RecommendedModsToggleCheckbox.Checked = true; m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose recommended mods"); } else { RecommendedDialogLabel.Text = "The following modules have been suggested by one or more of the chosen modules:"; RecommendedModsListView.Columns[1].Text = "Suggested by:"; RecommendedModsToggleCheckbox.Text = "(De-)select all suggested mods."; RecommendedModsToggleCheckbox.Checked = false; m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose suggested mods"); } RecommendedModsListView.Items.Clear(); foreach (KeyValuePair <string, List <string> > pair in mods) { CfanModule module; try { var opts = new RelationshipResolverOptions { with_all_suggests = false, with_recommends = false, with_suggests = false, without_enforce_consistency = false, without_toomanyprovides_kraken = true }; CfanModuleIdAndVersion[] arrayWithOneModName = new[] { new CfanModuleIdAndVersion(pair.Key) }; RelationshipResolver resolver = new RelationshipResolver(arrayWithOneModName, opts, RegistryManager.Instance(manager.CurrentInstance).registry, CurrentInstance.Version()); if (!resolver.ModList().Any()) { continue; } module = RegistryManager.Instance(manager.CurrentInstance) .registry.LatestAvailable(pair.Key, CurrentInstance.Version()); } catch { continue; } if (module == null) { continue; } ListViewItem item = new ListViewItem { Tag = module, Checked = !suggested, Text = pair.Key }; ListViewItem.ListViewSubItem recommendedBy = new ListViewItem.ListViewSubItem(); string recommendedByString = ""; bool first = true; foreach (string mod in pair.Value) { if (!first) { recommendedByString += ", "; } else { first = false; } recommendedByString += mod; } recommendedBy.Text = recommendedByString; item.SubItems.Add(recommendedBy); ListViewItem.ListViewSubItem description = new ListViewItem.ListViewSubItem { Text = module.@abstract }; item.SubItems.Add(description); RecommendedModsListView.Items.Add(item); } }