diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4af91e4b..32b233d95 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -59,6 +59,7 @@ All notable changes to this project will be documented in this file.
- [Multiple] Stop checking multiple hashes (#4135 by: HebaruSan)
- [Core] Fix max version column for wildcard compat (#4142 by: HebaruSan)
- [Multiple] Refactor ZIP importing (#4153 by: HebaruSan)
+- [GUI] Work around OpenFileDialog always showing all shortcuts despite filters (#4168 by: HebaruSan)
### Internal
diff --git a/Core/CkanTransaction.cs b/Core/CkanTransaction.cs
index cafdabfd4..f9d4ae504 100644
--- a/Core/CkanTransaction.cs
+++ b/Core/CkanTransaction.cs
@@ -26,7 +26,7 @@ public static TransactionScope CreateTransactionScope()
}
// System.ArgumentOutOfRangeException : Time-out interval must be less than 2^32-2. (Parameter 'dueTime')
- private const double timeoutMs = Int32.MaxValue;
+ private const double timeoutMs = int.MaxValue;
private static readonly TimeSpan maxCoretimeout = TimeSpan.FromMilliseconds(timeoutMs);
private static readonly TransactionOptions transOpts = new TransactionOptions()
diff --git a/Core/Configuration/JsonConfiguration.cs b/Core/Configuration/JsonConfiguration.cs
index db844f080..0ba771f42 100644
--- a/Core/Configuration/JsonConfiguration.cs
+++ b/Core/Configuration/JsonConfiguration.cs
@@ -75,7 +75,7 @@ public JsonConfiguration(string newConfig = null)
// If you have multiple instances of CKAN running at the same time, each will
// believe that their copy of the config file in memory is authoritative, so
// changes made by one copy will not be respected by the other.
- private string configFile = defaultConfigFile;
+ private readonly string configFile = defaultConfigFile;
private Config config = null;
public string DownloadCacheDir
diff --git a/GUI/Dialogs/ManageGameInstancesDialog.cs b/GUI/Dialogs/ManageGameInstancesDialog.cs
index 25a6b8465..4404220ca 100644
--- a/GUI/Dialogs/ManageGameInstancesDialog.cs
+++ b/GUI/Dialogs/ManageGameInstancesDialog.cs
@@ -18,42 +18,24 @@ namespace CKAN.GUI
#endif
public partial class ManageGameInstancesDialog : Form
{
- private static GameInstanceManager manager => Main.Instance.Manager;
- private readonly IUser _user;
- private RenameInstanceDialog _renameInstanceDialog;
- private readonly OpenFileDialog _instanceDialog = new OpenFileDialog()
- {
- AddExtension = false,
- CheckFileExists = false,
- CheckPathExists = false,
- InitialDirectory = Environment.CurrentDirectory,
- Filter = GameFolderFilter(manager),
- Multiselect = false
- };
-
- ///
- /// Generate filter string for OpenFileDialog
- ///
- /// Game instance manager that can tell us about the build ID files
- ///
- /// "Build metadata files (buildID.txt;buildID64.txt)|buildID.txt;buildID64.txt"
- ///
- public static string GameFolderFilter(GameInstanceManager mgr)
- => Properties.Resources.GameProgramFileDescription
- + "|" + string.Join(";", mgr.AllInstanceAnchorFiles);
-
- public bool HasSelections => GameInstancesListView.SelectedItems.Count > 0;
-
///
/// Initialize the game instance selection window
///
+ /// Game instance manager object to provide our game instances
/// true to center the window on the screen, false to center it on the parent
- public ManageGameInstancesDialog(bool centerScreen, IUser user)
+ /// IUser object reference for raising dialogs
+ public ManageGameInstancesDialog(GameInstanceManager mgr,
+ bool centerScreen,
+ IUser user)
{
- _user = user;
+ manager = mgr;
+ this.user = user;
InitializeComponent();
DialogResult = DialogResult.Cancel;
+ instanceDialog.Filter = GameFolderFilter(manager);
+ instanceDialog.FileOk += InstanceFileOK;
+
if (centerScreen)
{
StartPosition = FormStartPosition.CenterScreen;
@@ -101,6 +83,19 @@ public void UpdateInstancesList()
GameInstancesListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
}
+ ///
+ /// Generate filter string for OpenFileDialog
+ ///
+ /// Game instance manager that can tell us about the build ID files
+ ///
+ /// "Build metadata files (buildID.txt;buildID64.txt)|buildID.txt;buildID64.txt"
+ ///
+ public static string GameFolderFilter(GameInstanceManager mgr)
+ => Properties.Resources.GameProgramFileDescription
+ + "|" + string.Join(";", mgr.AllInstanceAnchorFiles);
+
+ public bool HasSelections => GameInstancesListView.SelectedItems.Count > 0;
+
private void AddOrRemoveColumn(ListView listView, ColumnHeader column, bool condition, int index)
{
if (condition && !listView.Columns.Contains(column))
@@ -157,22 +152,20 @@ protected override void OnHelpButtonClicked(CancelEventArgs evt)
}
private static string FormatVersion(GameVersion v)
- {
- return v == null
+ => v == null
? Properties.Resources.CompatibleGameVersionsDialogNone
// The BUILD component is not useful visually
: new GameVersion(v.Major, v.Minor, v.Patch).ToString();
- }
private void AddToCKANMenuItem_Click(object sender, EventArgs e)
{
- if (_instanceDialog.ShowDialog(this) != DialogResult.OK
- || !File.Exists(_instanceDialog.FileName))
+ if (instanceDialog.ShowDialog(this) != DialogResult.OK
+ || !File.Exists(instanceDialog.FileName))
{
return;
}
- var path = Path.GetDirectoryName(_instanceDialog.FileName);
+ var path = Path.GetDirectoryName(instanceDialog.FileName);
try
{
var instanceName = Path.GetFileName(path);
@@ -181,17 +174,17 @@ private void AddToCKANMenuItem_Click(object sender, EventArgs e)
instanceName = path;
}
instanceName = manager.GetNextValidInstanceName(instanceName);
- manager.AddInstance(path, instanceName, _user);
+ manager.AddInstance(path, instanceName, user);
UpdateInstancesList();
}
catch (NotKSPDirKraken k)
{
- _user.RaiseError(Properties.Resources.ManageGameInstancesNotValid,
+ user.RaiseError(Properties.Resources.ManageGameInstancesNotValid,
new object[] { k.path });
}
catch (Exception exc)
{
- _user.RaiseError(exc.Message);
+ user.RaiseError(exc.Message);
}
}
@@ -213,7 +206,7 @@ private void CloneGameInstanceMenuItem_Click(object sender, EventArgs e)
{
var old_instance = manager.CurrentInstance;
- var result = new CloneGameInstanceDialog(manager, _user, (string)GameInstancesListView.SelectedItems[0].Tag).ShowDialog(this);
+ var result = new CloneGameInstanceDialog(manager, user, (string)GameInstancesListView.SelectedItems[0].Tag).ShowDialog(this);
if (result == DialogResult.OK && !Equals(old_instance, manager.CurrentInstance))
{
DialogResult = DialogResult.OK;
@@ -246,7 +239,7 @@ private void UseSelectedInstance()
}
catch (NotKSPDirKraken k)
{
- _user.RaiseError(Properties.Resources.ManageGameInstancesNotValid, k.path);
+ user.RaiseError(Properties.Resources.ManageGameInstancesNotValid, k.path);
}
}
}
@@ -270,7 +263,7 @@ private void SetAsDefaultCheckbox_Click(object sender, EventArgs e)
}
catch (NotKSPDirKraken k)
{
- _user.RaiseError(Properties.Resources.ManageGameInstancesNotValid, k.path);
+ user.RaiseError(Properties.Resources.ManageGameInstancesNotValid, k.path);
}
}
}
@@ -321,7 +314,7 @@ private void OpenDirectoryMenuItem_Click(object sender, EventArgs e)
if (!Directory.Exists(path))
{
- _user.RaiseError(Properties.Resources.ManageGameInstancesDirectoryDeleted, path);
+ user.RaiseError(Properties.Resources.ManageGameInstancesDirectoryDeleted, path);
return;
}
@@ -333,14 +326,14 @@ private void RenameButton_Click(object sender, EventArgs e)
var instance = (string)GameInstancesListView.SelectedItems[0].Tag;
// show the dialog, and only continue if the user selected "OK"
- _renameInstanceDialog = new RenameInstanceDialog();
- if (_renameInstanceDialog.ShowRenameInstanceDialog(instance) != DialogResult.OK)
+ var renameInstanceDialog = new RenameInstanceDialog();
+ if (renameInstanceDialog.ShowRenameInstanceDialog(instance) != DialogResult.OK)
{
return;
}
// proceed with instance rename
- manager.RenameInstance(instance, _renameInstanceDialog.GetResult());
+ manager.RenameInstance(instance, renameInstanceDialog.GetResult());
UpdateInstancesList();
}
@@ -359,5 +352,39 @@ private void UpdateButtonState()
ForgetButton.Enabled = HasSelections && (string)GameInstancesListView.SelectedItems[0].Tag != manager.CurrentInstance?.Name;
ImportFromSteamMenuItem.Enabled = manager.SteamLibrary.Games.Length > 0;
}
+
+ private readonly GameInstanceManager manager;
+
+ private readonly IUser user;
+
+ private readonly OpenFileDialog instanceDialog = new OpenFileDialog()
+ {
+ AddExtension = false,
+ CheckFileExists = false,
+ CheckPathExists = false,
+ DereferenceLinks = false,
+ InitialDirectory = Environment.CurrentDirectory,
+ Multiselect = false,
+ };
+
+ private void InstanceFileOK(object sender, CancelEventArgs e)
+ {
+ if (sender is OpenFileDialog dlg)
+ {
+ // OpenFileDialog always shows shortcuts (!!!!!),
+ // so we have to re-enforce the filter ourselves
+ var chosen = Path.GetFileName(dlg.FileName);
+ var allowed = manager.AllInstanceAnchorFiles;
+ if (!allowed.Contains(chosen))
+ {
+ e.Cancel = true;
+ user.RaiseError(Properties.Resources.ManageGameInstancesInvalidFileSelected,
+ chosen,
+ string.Join(Environment.NewLine,
+ allowed.OrderBy(f => f)
+ .Select(f => $" - {f}")));
+ }
+ }
+ }
}
}
diff --git a/GUI/Main/Main.cs b/GUI/Main/Main.cs
index 3371279a7..d5dfc211f 100644
--- a/GUI/Main/Main.cs
+++ b/GUI/Main/Main.cs
@@ -326,7 +326,7 @@ private bool InstancePromptAtStart()
bool gotInstance = false;
Util.Invoke(this, () =>
{
- var result = new ManageGameInstancesDialog(!actuallyVisible, currentUser).ShowDialog(this);
+ var result = new ManageGameInstancesDialog(Manager, !actuallyVisible, currentUser).ShowDialog(this);
gotInstance = result == DialogResult.OK;
});
return gotInstance;
@@ -335,7 +335,7 @@ private bool InstancePromptAtStart()
private void manageGameInstancesMenuItem_Click(object sender, EventArgs e)
{
var old_instance = CurrentInstance;
- var result = new ManageGameInstancesDialog(!actuallyVisible, currentUser).ShowDialog(this);
+ var result = new ManageGameInstancesDialog(Manager, !actuallyVisible, currentUser).ShowDialog(this);
if (result == DialogResult.OK && !Equals(old_instance, CurrentInstance))
{
for (bool done = false; !done;)
diff --git a/GUI/Model/ModList.cs b/GUI/Model/ModList.cs
index 52420350d..f99abbc0e 100644
--- a/GUI/Model/ModList.cs
+++ b/GUI/Model/ModList.cs
@@ -193,7 +193,7 @@ public Tuple, Dictionary, List, Dictionary, ListCompatible versions of current instance
/// Sequence of InstalledModules after the changes are applied, not including dependencies
private IEnumerable InstalledAfterChanges(
- IRegistryQuerier registry, HashSet changeSet, GameVersionCriteria crit)
+ IRegistryQuerier registry, HashSet changeSet)
{
var removingIdents = changeSet
.Where(ch => ch.ChangeType != GUIModChangeType.Install)
diff --git a/GUI/Properties/Resources.resx b/GUI/Properties/Resources.resx
index b0a6f2c36..0867ac38f 100644
--- a/GUI/Properties/Resources.resx
+++ b/GUI/Properties/Resources.resx
@@ -344,6 +344,13 @@ You can refresh the mod list manually with the Refresh button at the top, and yo
Directory "{0}" doesn't exist.
{0} (INVALID)
{0} (LOCKED)
+ Not a valid game instance file: "{0}"
+
+If you selected a shortcut, don't do that; Windows won't let us hide them from this dialog even though they're invalid.
+
+Find the folder where your game is installed and choose one of these files:
+
+{1}
Failed to fetch master list.
CKAN Plugins (*.dll)|*.dll
{0} files, {1}, {2} free
diff --git a/Netkan/Transformers/InternalCkanTransformer.cs b/Netkan/Transformers/InternalCkanTransformer.cs
index 044b3db2f..7d75ab000 100644
--- a/Netkan/Transformers/InternalCkanTransformer.cs
+++ b/Netkan/Transformers/InternalCkanTransformer.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using log4net;
-using CKAN.Versioning;
using CKAN.NetKAN.Extensions;
using CKAN.NetKAN.Model;
using CKAN.NetKAN.Services;
diff --git a/Netkan/Transformers/MetaNetkanTransformer.cs b/Netkan/Transformers/MetaNetkanTransformer.cs
index f20ca66fe..ace4040ae 100644
--- a/Netkan/Transformers/MetaNetkanTransformer.cs
+++ b/Netkan/Transformers/MetaNetkanTransformer.cs
@@ -5,7 +5,6 @@
using log4net;
using Newtonsoft.Json.Linq;
-using CKAN.Versioning;
using CKAN.NetKAN.Extensions;
using CKAN.NetKAN.Model;
using CKAN.NetKAN.Services;