diff --git a/src/KKManager.Core/Functions/ZipmodTools.cs b/src/KKManager.Core/Functions/ZipmodTools.cs
index 6fa30e3..2b669fe 100644
--- a/src/KKManager.Core/Functions/ZipmodTools.cs
+++ b/src/KKManager.Core/Functions/ZipmodTools.cs
@@ -4,6 +4,7 @@
using System.IO;
using System.Linq;
using KKManager.Data.Zipmods;
+using KKManager.Util;
namespace KKManager.Windows
{
@@ -121,7 +122,7 @@ private static void SafeFileDelete(string file)
try
{
if (!_simulate)
- File.Delete(file);
+ file.SafeDelete().Wait();
}
catch (SystemException)
{
diff --git a/src/KKManager.Core/KKManager.Core.csproj b/src/KKManager.Core/KKManager.Core.csproj
index 5ee28f2..16dd65b 100644
--- a/src/KKManager.Core/KKManager.Core.csproj
+++ b/src/KKManager.Core/KKManager.Core.csproj
@@ -70,6 +70,7 @@
..\packages\Microsoft.NET.StringTools.17.7.2\lib\net472\Microsoft.NET.StringTools.dll
+
..\packages\Mono.Cecil.0.11.5\lib\net40\Mono.Cecil.dll
diff --git a/src/KKManager.Core/Properties/Settings.Designer.cs b/src/KKManager.Core/Properties/Settings.Designer.cs
index cff521e..f5963f4 100644
--- a/src/KKManager.Core/Properties/Settings.Designer.cs
+++ b/src/KKManager.Core/Properties/Settings.Designer.cs
@@ -12,7 +12,7 @@ namespace KKManager.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.8.0.0")]
public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -199,5 +199,17 @@ public bool P2P_SettingsShown {
this["P2P_SettingsShown"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("True")]
+ public bool DeleteToRecycleBin {
+ get {
+ return ((bool)(this["DeleteToRecycleBin"]));
+ }
+ set {
+ this["DeleteToRecycleBin"] = value;
+ }
+ }
}
}
diff --git a/src/KKManager.Core/Properties/Settings.settings b/src/KKManager.Core/Properties/Settings.settings
index b55d0ac..3bec94e 100644
--- a/src/KKManager.Core/Properties/Settings.settings
+++ b/src/KKManager.Core/Properties/Settings.settings
@@ -44,5 +44,8 @@
False
+
+ True
+
\ No newline at end of file
diff --git a/src/KKManager.Core/Util/Extensions.cs b/src/KKManager.Core/Util/Extensions.cs
index deaa388..3ca7345 100644
--- a/src/KKManager.Core/Util/Extensions.cs
+++ b/src/KKManager.Core/Util/Extensions.cs
@@ -2,12 +2,15 @@
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using BrightIdeasSoftware;
+using KKManager.Properties;
+using Microsoft.VisualBasic.FileIO;
using SharpCompress.Archives;
using SharpCompress.Readers;
@@ -113,7 +116,7 @@ public static string GetFullNameWithDifferentExtension(this FileInfo fi, string
{
if (fi == null) throw new ArgumentNullException(nameof(fi));
if (newExtension == null) throw new ArgumentNullException(nameof(newExtension));
-
+
return Path.Combine(fi.DirectoryName ?? throw new InvalidOperationException("DirectoryName null for " + fi),
fi.GetNameWithoutExtension() + newExtension);
}
@@ -141,5 +144,75 @@ public static XElement GetOrAddElement(this XElement e, string name)
public static void AddObjects(this ObjectListView olv, IList modelObjects) => olv.AddObjects((ICollection)modelObjects);
public static void RefreshObjects(this ObjectListView olv, IList modelObjects) => olv.RefreshObjects((IList)modelObjects);
+
+ public static async Task SafeDelete(this FileSystemInfo info)
+ {
+ if (info == null) return;
+
+ var toRecycleBin = Settings.Default.DeleteToRecycleBin;
+
+ try
+ {
+ if (info.Exists)
+ {
+ // Prevent issues removing readonly files
+ info.Attributes = FileAttributes.Normal;
+
+ if (info is DirectoryInfo dir)
+ {
+ try
+ {
+ if (toRecycleBin)
+ FileSystem.DeleteDirectory(dir.FullName, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
+ else
+ dir.Delete(true);
+ }
+ catch
+ {
+ await Task.Delay(100);
+ dir.Delete(true);
+ }
+ }
+ else if (info is FileInfo file)
+ {
+ try
+ {
+ if (toRecycleBin)
+ FileSystem.DeleteFile(file.FullName, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
+ else
+ file.Delete();
+ }
+ catch
+ {
+ await Task.Delay(100);
+ file.Delete();
+ }
+ }
+ else
+ {
+ throw new InvalidOperationException("wtf is" + info.GetType().AssemblyQualifiedName);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (ex is AggregateException ae && ae.InnerExceptions.Count == 1)
+ ex = ae.InnerExceptions[0];
+
+ Console.WriteLine($"Failed to delete [{info.FullName}] because of error: {ex.ToStringDemystified()}");
+
+ throw;
+ }
+ }
+
+ public static Task SafeDelete(this string filename)
+ {
+ if (File.Exists(filename))
+ return new FileInfo(filename).SafeDelete();
+ else if (Directory.Exists(filename))
+ return new DirectoryInfo(filename).SafeDelete();
+ else
+ return Task.CompletedTask;
+ }
}
}
diff --git a/src/KKManager.Core/app.config b/src/KKManager.Core/app.config
index 0bb9c3d..e8c17bc 100644
--- a/src/KKManager.Core/app.config
+++ b/src/KKManager.Core/app.config
@@ -97,6 +97,9 @@
False
+
+ True
+
diff --git a/src/KKManager.Updater/Data/UpdateItem.cs b/src/KKManager.Updater/Data/UpdateItem.cs
index 2e6ceee..9f0be4f 100644
--- a/src/KKManager.Updater/Data/UpdateItem.cs
+++ b/src/KKManager.Updater/Data/UpdateItem.cs
@@ -111,9 +111,7 @@ public async Task Update(Progress progressCallback, CancellationToken ca
if (TargetPath.Exists)
{
Console.WriteLine($"Deleting old file {TargetPath.FullName}");
- // Prevent issues removing readonly files
- TargetPath.Attributes = FileAttributes.Normal;
- TargetPath.Delete();
+ await TargetPath.SafeDelete();
// Make sure the file gets deleted before continuing
await Task.Delay(200, cancellationToken).ConfigureAwait(false);
}
diff --git a/src/KKManager.Updater/Sources/FtpUpdater.cs b/src/KKManager.Updater/Sources/FtpUpdater.cs
index a4168e5..2a88839 100644
--- a/src/KKManager.Updater/Sources/FtpUpdater.cs
+++ b/src/KKManager.Updater/Sources/FtpUpdater.cs
@@ -208,7 +208,7 @@ private IEnumerable GetSubNodes(FtpListItem remoteDir)
private async Task UpdateItem(FtpListItem sourceItem, FileInfo targetPath, IProgress progressCallback, CancellationToken cancellationToken)
{
// Delete old file if any exists so the download doesn't try to append to it. Append mode is needed for retrying downloads to resume instead of restarting
- targetPath.Delete();
+ await targetPath.SafeDelete();
await Connect(cancellationToken).ConfigureAwait(false);
diff --git a/src/KKManager/Windows/Content/CardWindow.cs b/src/KKManager/Windows/Content/CardWindow.cs
index 7c5f786..25863c8 100644
--- a/src/KKManager/Windows/Content/CardWindow.cs
+++ b/src/KKManager/Windows/Content/CardWindow.cs
@@ -560,7 +560,7 @@ private void renameCardsToolStripMenuItem_Click(object sender, EventArgs e)
RenameCards.ShowDialog(this, _typedListView.SelectedObjects.ToArray());
}
- private void toolStripButtonDelete_Click(object sender, EventArgs e)
+ private async void toolStripButtonDelete_Click(object sender, EventArgs e)
{
var selectedObjects = _typedListView.SelectedObjects;
if (!selectedObjects.Any()) return;
@@ -571,7 +571,7 @@ private void toolStripButtonDelete_Click(object sender, EventArgs e)
{
try
{
- selectedObject.Location.Delete();
+ await selectedObject.Location.SafeDelete();
}
catch (Exception exception)
{
diff --git a/src/KKManager/Windows/Content/PluginsWindow.cs b/src/KKManager/Windows/Content/PluginsWindow.cs
index 9351048..a475512 100644
--- a/src/KKManager/Windows/Content/PluginsWindow.cs
+++ b/src/KKManager/Windows/Content/PluginsWindow.cs
@@ -97,7 +97,7 @@ private void SideloaderModsWindow_FormClosed(object sender, FormClosedEventArgs
CancelRefreshing();
}
- private void toolStripButtonDelete_Click(object sender, EventArgs e)
+ private async void toolStripButtonDelete_Click(object sender, EventArgs e)
{
if (MessageBox.Show("This will permanently delete all selected plugins, are you sure you want to continue?",
"Delete plugins", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
@@ -116,7 +116,7 @@ private void toolStripButtonDelete_Click(object sender, EventArgs e)
{
try
{
- plug.Location.Delete();
+ await plug.Location.SafeDelete();
objectListView1.RemoveObject(plug);
}
catch (SystemException ex)
diff --git a/src/KKManager/Windows/Content/SideloaderModsWindow.cs b/src/KKManager/Windows/Content/SideloaderModsWindow.cs
index 57341c1..a2f8455 100644
--- a/src/KKManager/Windows/Content/SideloaderModsWindow.cs
+++ b/src/KKManager/Windows/Content/SideloaderModsWindow.cs
@@ -129,7 +129,7 @@ private void toolStripButtonDisable_Click(object sender, EventArgs e)
SetZipmodEnabled(false, _listView.SelectedObjects);
}
- private void toolStripButtonDelete_Click(object sender, EventArgs e)
+ private async void toolStripButtonDelete_Click(object sender, EventArgs e)
{
if (MessageBox.Show("This will permanently delete all selected zipmods, are you sure you want to continue?",
"Delete zipmods", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
@@ -139,7 +139,7 @@ private void toolStripButtonDelete_Click(object sender, EventArgs e)
{
try
{
- obj.Location.Delete();
+ await obj.Location.SafeDelete();
objectListView1.RemoveObject(obj);
}
catch (SystemException ex)
diff --git a/src/KKManager/Windows/MainWindow.Designer.cs b/src/KKManager/Windows/MainWindow.Designer.cs
index 4365ef3..dc8b842 100644
--- a/src/KKManager/Windows/MainWindow.Designer.cs
+++ b/src/KKManager/Windows/MainWindow.Designer.cs
@@ -33,6 +33,8 @@ private void InitializeComponent()
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow));
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.openGameLogToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
this.changeGameInstallDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -85,8 +87,7 @@ private void InitializeComponent()
this.dockPanel = new WeifenLuo.WinFormsUI.Docking.DockPanel();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabelStatus = new System.Windows.Forms.ToolStripStatusLabel();
- this.openGameLogToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
- this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
+ this.tryToDeleteToRecycleBinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.SuspendLayout();
@@ -118,6 +119,17 @@ private void InitializeComponent()
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
resources.ApplyResources(this.fileToolStripMenuItem, "fileToolStripMenuItem");
//
+ // openGameLogToolStripMenuItem
+ //
+ this.openGameLogToolStripMenuItem.Name = "openGameLogToolStripMenuItem";
+ resources.ApplyResources(this.openGameLogToolStripMenuItem, "openGameLogToolStripMenuItem");
+ this.openGameLogToolStripMenuItem.Click += new System.EventHandler(this.openGameLogToolStripMenuItem_Click);
+ //
+ // toolStripSeparator7
+ //
+ this.toolStripSeparator7.Name = "toolStripSeparator7";
+ resources.ApplyResources(this.toolStripSeparator7, "toolStripSeparator7");
+ //
// changeGameInstallDirectoryToolStripMenuItem
//
this.changeGameInstallDirectoryToolStripMenuItem.Name = "changeGameInstallDirectoryToolStripMenuItem";
@@ -377,7 +389,8 @@ private void InitializeComponent()
// settingsToolStripMenuItem
//
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.languagesToolStripMenuItem});
+ this.languagesToolStripMenuItem,
+ this.tryToDeleteToRecycleBinToolStripMenuItem});
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
resources.ApplyResources(this.settingsToolStripMenuItem, "settingsToolStripMenuItem");
this.settingsToolStripMenuItem.DropDownOpening += new System.EventHandler(this.settingsToolStripMenuItem_DropDownOpening);
@@ -457,16 +470,10 @@ private void InitializeComponent()
this.toolStripStatusLabelStatus.Name = "toolStripStatusLabelStatus";
resources.ApplyResources(this.toolStripStatusLabelStatus, "toolStripStatusLabelStatus");
//
- // openGameLogToolStripMenuItem
- //
- this.openGameLogToolStripMenuItem.Name = "openGameLogToolStripMenuItem";
- resources.ApplyResources(this.openGameLogToolStripMenuItem, "openGameLogToolStripMenuItem");
- this.openGameLogToolStripMenuItem.Click += new System.EventHandler(this.openGameLogToolStripMenuItem_Click);
- //
- // toolStripSeparator7
+ // tryToDeleteToRecycleBinToolStripMenuItem
//
- this.toolStripSeparator7.Name = "toolStripSeparator7";
- resources.ApplyResources(this.toolStripSeparator7, "toolStripSeparator7");
+ this.tryToDeleteToRecycleBinToolStripMenuItem.Name = "tryToDeleteToRecycleBinToolStripMenuItem";
+ resources.ApplyResources(this.tryToDeleteToRecycleBinToolStripMenuItem, "tryToDeleteToRecycleBinToolStripMenuItem");
//
// MainWindow
//
@@ -547,5 +554,6 @@ private void InitializeComponent()
private ToolStripMenuItem openIndividualDownloadWebsiteToolStripMenuItem;
private ToolStripMenuItem openGameLogToolStripMenuItem;
private ToolStripSeparator toolStripSeparator7;
+ private ToolStripMenuItem tryToDeleteToRecycleBinToolStripMenuItem;
}
}
\ No newline at end of file
diff --git a/src/KKManager/Windows/MainWindow.cs b/src/KKManager/Windows/MainWindow.cs
index d6d304e..dda58de 100644
--- a/src/KKManager/Windows/MainWindow.cs
+++ b/src/KKManager/Windows/MainWindow.cs
@@ -65,6 +65,7 @@ public MainWindow()
Settings.Default.Binder.BindControl(checkForUpdatesOnStartupToolStripMenuItem, settings => settings.AutoUpdateSearch, this);
Settings.Default.Binder.BindControl(useSystemProxyServerToolStripMenuItem, settings => settings.UseProxy, this);
+ Settings.Default.Binder.BindControl(tryToDeleteToRecycleBinToolStripMenuItem, settings => settings.DeleteToRecycleBin, this);
Settings.Default.Binder.SendUpdates(this);
// Before using the window location, check if isn't the default value and that it's actually visible on the screen
diff --git a/src/KKManager/Windows/MainWindow.resx b/src/KKManager/Windows/MainWindow.resx
index ece5de8..304e06c 100644
--- a/src/KKManager/Windows/MainWindow.resx
+++ b/src/KKManager/Windows/MainWindow.resx
@@ -356,11 +356,22 @@
&Tools
- 126, 22
+ 215, 22
Language
+
+ 215, 22
+
+
+ Try to delete to Recycle Bin
+
+
+ Attempt to move files to the recycle bin when deleting cards/mods/plugins and when updating mods.
+If this fails for whatever reason (e.g. recycle bin is full or disabled) the files are deleted permanently.
+
+
61, 20
@@ -2164,6 +2175,18 @@
System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ openGameLogToolStripMenuItem
+
+
+ System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ toolStripSeparator7
+
+
+ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
changeGameInstallDirectoryToolStripMenuItem
@@ -2464,18 +2487,12 @@
System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- openGameLogToolStripMenuItem
+
+ tryToDeleteToRecycleBinToolStripMenuItem
-
+
System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- toolStripSeparator7
-
-
- System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
MainWindow