diff --git a/CHANGELOG.md b/CHANGELOG.md
index a647936e4..367fd6428 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
- [CLI] Include `supports` relationship in `ckan show` (#4262 by: HebaruSan)
- [Multiple] Pre-release handling (#4260, #4266, #4294 by: HebaruSan, JonnyOThan)
- [Multiple] French translation updates (#4268 by: HebaruSan)
+- [Multiple] Checkboxes to copy more dirs when cloning instances (#4304 by: HebaruSan)
### Bugfixes
diff --git a/Core/GameInstanceManager.cs b/Core/GameInstanceManager.cs
index f0e6b1648..f2c458459 100644
--- a/Core/GameInstanceManager.cs
+++ b/Core/GameInstanceManager.cs
@@ -243,6 +243,7 @@ public GameInstance AddInstance(GameInstance instance)
/// The KSP instance to clone.
/// The name for the new instance.
/// The path where the new instance should be located.
+ /// True to make junctions or symlinks to stock folders instead of copying
/// Thrown if the instance name is already in use.
/// Thrown by AddInstance() if created instance is not valid, e.g. if something went wrong with copying.
/// Thrown by CopyDirectory() if directory doesn't exist. Should never be thrown here.
@@ -252,6 +253,30 @@ public void CloneInstance(GameInstance existingInstance,
string newName,
string newPath,
bool shareStockFolders = false)
+ {
+ CloneInstance(existingInstance, newName, newPath,
+ existingInstance.game.LeaveEmptyInClones,
+ shareStockFolders);
+ }
+
+ ///
+ /// Clones an existing KSP installation.
+ ///
+ /// The KSP instance to clone.
+ /// The name for the new instance.
+ /// The path where the new instance should be located.
+ /// Dirs whose contents should not be copied
+ /// True to make junctions or symlinks to stock folders instead of copying
+ /// Thrown if the instance name is already in use.
+ /// Thrown by AddInstance() if created instance is not valid, e.g. if something went wrong with copying.
+ /// Thrown by CopyDirectory() if directory doesn't exist. Should never be thrown here.
+ /// Thrown by CopyDirectory() if the target folder already exists and is not empty.
+ /// Thrown by CopyDirectory() if something goes wrong during the process.
+ public void CloneInstance(GameInstance existingInstance,
+ string newName,
+ string newPath,
+ string[] leaveEmpty,
+ bool shareStockFolders = false)
{
if (HasInstance(newName))
{
@@ -267,7 +292,7 @@ public void CloneInstance(GameInstance existingInstance,
Utilities.CopyDirectory(existingInstance.GameDir(), newPath,
shareStockFolders ? existingInstance.game.StockFolders
: Array.Empty(),
- existingInstance.game.LeaveEmptyInClones);
+ leaveEmpty);
// Add the new instance to the config
AddInstance(new GameInstance(existingInstance.game, newPath, newName, User));
diff --git a/GUI/Dialogs/CloneGameInstanceDialog.Designer.cs b/GUI/Dialogs/CloneGameInstanceDialog.Designer.cs
index dbe1c2d05..7aa57c7f3 100644
--- a/GUI/Dialogs/CloneGameInstanceDialog.Designer.cs
+++ b/GUI/Dialogs/CloneGameInstanceDialog.Designer.cs
@@ -44,6 +44,9 @@ private void InitializeComponent()
this.checkBoxSetAsDefault = new System.Windows.Forms.CheckBox();
this.checkBoxSwitchInstance = new System.Windows.Forms.CheckBox();
this.checkBoxShareStock = new System.Windows.Forms.CheckBox();
+ this.OptionalPathsLabel = new System.Windows.Forms.Label();
+ this.OptionalPathsListView = new ThemedListView();
+ this.PathHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.buttonOK = new System.Windows.Forms.Button();
this.buttonCancel = new System.Windows.Forms.Button();
this.progressBar = new System.Windows.Forms.ProgressBar();
@@ -196,10 +199,39 @@ private void InitializeComponent()
this.checkBoxShareStock.UseVisualStyleBackColor = true;
resources.ApplyResources(this.checkBoxShareStock, "checkBoxShareStock");
//
+ // OptionalPathsLabel
+ //
+ this.OptionalPathsLabel.AutoSize = true;
+ this.OptionalPathsLabel.Location = new System.Drawing.Point(12, 234);
+ this.OptionalPathsLabel.Name = "OptionalPathsLabel";
+ this.OptionalPathsLabel.Size = new System.Drawing.Size(131, 13);
+ this.OptionalPathsLabel.TabIndex = 22;
+ resources.ApplyResources(this.OptionalPathsLabel, "OptionalPathsLabel");
+ //
+ // OptionalPathsListView
+ //
+ this.OptionalPathsListView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.OptionalPathsListView.CheckBoxes = true;
+ this.OptionalPathsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.PathHeader});
+ this.OptionalPathsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
+ this.OptionalPathsListView.Location = new System.Drawing.Point(181, 234);
+ this.OptionalPathsListView.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
+ this.OptionalPathsListView.Name = "OptionalPathsListView";
+ this.OptionalPathsListView.Size = new System.Drawing.Size(218, 120);
+ this.OptionalPathsListView.TabIndex = 23;
+ this.OptionalPathsListView.UseCompatibleStateImageBehavior = false;
+ this.OptionalPathsListView.View = System.Windows.Forms.View.Details;
+ //
+ // PathHeader
+ //
+ this.PathHeader.Width = 180;
+ resources.ApplyResources(this.PathHeader, "PathHeader");
+ //
// buttonOK
//
this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.buttonOK.Location = new System.Drawing.Point(256, 230);
+ this.buttonOK.Location = new System.Drawing.Point(256, 360);
this.buttonOK.Name = "buttonOK";
this.buttonOK.Size = new System.Drawing.Size(75, 23);
this.buttonOK.TabIndex = 22;
@@ -210,7 +242,7 @@ private void InitializeComponent()
// buttonCancel
//
this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.buttonCancel.Location = new System.Drawing.Point(337, 230);
+ this.buttonCancel.Location = new System.Drawing.Point(337, 360);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
this.buttonCancel.TabIndex = 23;
@@ -235,7 +267,7 @@ private void InitializeComponent()
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(424, 265);
+ this.ClientSize = new System.Drawing.Size(424, 395);
this.Controls.Add(this.labelOldInstance);
this.Controls.Add(this.comboBoxKnownInstance);
this.Controls.Add(this.labelOldPath);
@@ -245,6 +277,8 @@ private void InitializeComponent()
this.Controls.Add(this.buttonPathBrowser);
this.Controls.Add(this.checkBoxSwitchInstance);
this.Controls.Add(this.checkBoxShareStock);
+ this.Controls.Add(this.OptionalPathsLabel);
+ this.Controls.Add(this.OptionalPathsListView);
this.Controls.Add(this.textBoxNewPath);
this.Controls.Add(this.labelNewPath);
this.Controls.Add(this.checkBoxSetAsDefault);
@@ -284,6 +318,9 @@ private void InitializeComponent()
private System.Windows.Forms.CheckBox checkBoxSetAsDefault;
private System.Windows.Forms.CheckBox checkBoxSwitchInstance;
private System.Windows.Forms.CheckBox checkBoxShareStock;
+ private System.Windows.Forms.Label OptionalPathsLabel;
+ private System.Windows.Forms.ListView OptionalPathsListView;
+ private System.Windows.Forms.ColumnHeader PathHeader;
private System.Windows.Forms.Button buttonOK;
private System.Windows.Forms.Button buttonCancel;
private System.Windows.Forms.FolderBrowserDialog folderBrowserDialogNewPath;
diff --git a/GUI/Dialogs/CloneGameInstanceDialog.cs b/GUI/Dialogs/CloneGameInstanceDialog.cs
index 796bab75f..12d101e6c 100644
--- a/GUI/Dialogs/CloneGameInstanceDialog.cs
+++ b/GUI/Dialogs/CloneGameInstanceDialog.cs
@@ -57,10 +57,21 @@ public CloneGameInstanceDialog(GameInstanceManager manager,
private void comboBoxKnownInstance_SelectedIndexChanged(object? sender, EventArgs? e)
{
- textBoxClonePath.Text = comboBoxKnownInstance.SelectedItem is string sel
- && !string.IsNullOrEmpty(sel)
- ? Platform.FormatPath(manager.Instances[sel].GameDir())
- : "";
+ if (comboBoxKnownInstance.SelectedItem is string sel
+ && !string.IsNullOrEmpty(sel))
+ {
+ var inst = manager.Instances[sel];
+ textBoxClonePath.Text = Platform.FormatPath(inst.GameDir());
+ OptionalPathsListView.Items.Clear();
+ OptionalPathsListView.Items.AddRange(
+ inst.game.LeaveEmptyInClones
+ .OrderBy(path => path,
+ StringComparer.OrdinalIgnoreCase)
+ .Select(path => new ListViewItem(path) { Tag = path })
+ .ToArray());
+ OptionalPathsLabel.Visible = OptionalPathsListView.Visible =
+ OptionalPathsListView.Items.Count > 0;
+ }
}
///
@@ -143,7 +154,14 @@ await Task.Run(() =>
{
if (instanceToClone.Valid)
{
- manager.CloneInstance(instanceToClone, newName, newPath, checkBoxShareStock.Checked);
+ manager.CloneInstance(instanceToClone, newName, newPath,
+ OptionalPathsListView.Items
+ .OfType()
+ .Where(lvi => !lvi.Checked)
+ .Select(lvi => lvi.Tag)
+ .OfType()
+ .ToArray(),
+ checkBoxShareStock.Checked);
}
else
{
diff --git a/GUI/Dialogs/CloneGameInstanceDialog.resx b/GUI/Dialogs/CloneGameInstanceDialog.resx
index a40d752b1..bba8c30fd 100644
--- a/GUI/Dialogs/CloneGameInstanceDialog.resx
+++ b/GUI/Dialogs/CloneGameInstanceDialog.resx
@@ -126,6 +126,8 @@
Set new instance as default
Switch to new instance
Share stock files
+ Optional paths to copy:
+ Optional paths
Clone
Cancel
Clone Game Instance