Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eed41bbcc7 | ||
|
|
238cb9e984 | ||
|
|
04c6ac3b8a | ||
|
|
e7aa0b56c4 | ||
|
|
80071ade8e |
@@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: radi0
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
@@ -4,4 +4,4 @@ WPF MVVM version of my link tool, faster, better, stronger.
|
||||
If you used my old versions, your xml instances won't load but your DB folder will be compatible.
|
||||
Just use the old tools to make links somewhere and add them as instances (copy files) using the WPF version.
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -10,7 +10,7 @@ namespace WPFLinkTool
|
||||
public class Global
|
||||
{
|
||||
//public static string curDir = @"F:\Torrents\bemaniso.ws\HardLinkUI";
|
||||
//public static string curDir = @"C:\Tools and stuff\WPFLinkTool";
|
||||
//public static string curDir = @"C:\Tools&Stuff\LinkToolTest";
|
||||
public static string curDir = Directory.GetCurrentDirectory();
|
||||
public static string dbDir = curDir + @"\DB";
|
||||
public static string xmlDir = curDir + @"\XML";
|
||||
|
||||
+29
-33
@@ -5,9 +5,20 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WPFLinkTool"
|
||||
mc:Ignorable="d"
|
||||
Title="MainWindow" Height="450" Width="500">
|
||||
<Border Padding="10">
|
||||
<StackPanel>
|
||||
Title="kors k's How to save a lot of disk space for your totally legal japanese rhythm games" Height="400" Width="650">
|
||||
<Border Padding="4">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition MaxHeight="16" MinHeight="16"></RowDefinition>
|
||||
<RowDefinition MaxHeight="24" MinHeight="24"></RowDefinition>
|
||||
<RowDefinition></RowDefinition>
|
||||
<RowDefinition MaxHeight="24" MinHeight="24"></RowDefinition>
|
||||
<RowDefinition MaxHeight="16" MinHeight="16"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -18,47 +29,32 @@
|
||||
<TextBlock Grid.Column="1" Text="{Binding SumSize, StringFormat=Instance size sum: {0}}"></TextBlock>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0 2 0 2">
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Command="{Binding OpenAddInstanceWindow}" Grid.Column="0">Add instance</Button>
|
||||
<Button IsEnabled="{Binding UIEnabled}" Command="{Binding OpenAddInstanceWindow}" Grid.Column="0">Add instance</Button>
|
||||
<Button IsEnabled="{Binding LinkButtonEnabled}" Command="{Binding MakeHardLinksCommand}" Grid.Column="1">Make hard links</Button>
|
||||
<Button IsEnabled="{Binding UIEnabled}" Command="{Binding DeleteUnusedCommand}" Grid.Column="2">Delete unused files</Button>
|
||||
<Button IsEnabled="{Binding LinkButtonEnabled}" Command="{Binding DeleteInstanceCommand}" Grid.Column="3">Delete instance</Button>
|
||||
</Grid>
|
||||
<DataGrid Grid.Row="2" ItemsSource="{Binding InstanceList}" AutoGenerateColumns="False" SelectedItem="{Binding SelectedInstance, Mode=TwoWay}"
|
||||
IsReadOnly="True" SelectionMode="Single" SelectionUnit="FullRow" CanUserReorderColumns="False"
|
||||
CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" HeadersVisibility="Column"
|
||||
ScrollViewer.CanContentScroll="True">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Name" Binding="{Binding InstanceName}" Width="3*"></DataGridTextColumn>
|
||||
<DataGridTextColumn Header="File count" Binding="{Binding Entries}" Width="1*"></DataGridTextColumn>
|
||||
<DataGridTextColumn Header="Instance size" Binding="{Binding PrettySize}" Width="1*" SortMemberPath="Size"></DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<ProgressBar Grid.Row="3" Value="{Binding Progress}" MinHeight="20"></ProgressBar>
|
||||
|
||||
<DockPanel MaxHeight="300" Margin="0 2 0 2">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible">
|
||||
<ItemsControl ItemsSource="{Binding InstanceList}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16"></ColumnDefinition>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton x:Name="RdioBtn" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=DataContext.SelectedInstanceCommand}" CommandParameter="{Binding ElementName=InstName, Path=Text}" Grid.Column="0" GroupName="InstanceGroup"></RadioButton>
|
||||
<TextBlock HorizontalAlignment="Center" x:Name="InstName" Grid.Column="1" Text="{Binding InstanceName}"></TextBlock>
|
||||
<TextBlock HorizontalAlignment="Center" Grid.Column="2" Text="{Binding Entries, StringFormat={}{0} files}"></TextBlock>
|
||||
<TextBlock HorizontalAlignment="Center" Grid.Column="3" Text="{Binding PrettySize}"></TextBlock>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
<TextBlock Grid.Row="4" Text="{Binding HeaderText}"></TextBlock>
|
||||
|
||||
<ProgressBar Margin="0 2 0 2" Value="{Binding Progress}" MinHeight="20"></ProgressBar>
|
||||
|
||||
<TextBlock Text="{Binding HeaderText}"></TextBlock>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
@@ -22,6 +22,7 @@ namespace WPFLinkTool
|
||||
{
|
||||
IsExecuting = true;
|
||||
vm.UIEnabled = false;
|
||||
vm.LinkButtonEnabled = false;
|
||||
|
||||
HashSet<string> dBFiles = new();
|
||||
DirectoryInfo dir = new(dbDir);
|
||||
@@ -55,6 +56,7 @@ namespace WPFLinkTool
|
||||
|
||||
vm.Progress = 0;
|
||||
vm.UIEnabled = true;
|
||||
vm.LinkButtonEnabled = true;
|
||||
IsExecuting = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using static WPFLinkTool.Global;
|
||||
@@ -14,21 +11,21 @@ namespace WPFLinkTool
|
||||
public class MakeHardLinksCommand : AsyncCommandBase
|
||||
{
|
||||
private readonly MainWindowViewModel vm;
|
||||
|
||||
private bool proceed = false;
|
||||
private bool delet = false;
|
||||
private string target;
|
||||
|
||||
public MakeHardLinksCommand(MainWindowViewModel viewmodel, Action<Exception> onException) : base(onException)
|
||||
{
|
||||
vm = viewmodel;
|
||||
vm = viewmodel;
|
||||
}
|
||||
|
||||
|
||||
protected override async Task ExecuteAsync(object parameter)
|
||||
{
|
||||
IsExecuting = true;
|
||||
vm.UIEnabled = false;
|
||||
string selInst = vm.SelectedInstance;
|
||||
var selectedInstance = (from inst in vm.Shared.Info.InstanceList
|
||||
where inst.InstanceName == selInst
|
||||
select inst).Single();
|
||||
|
||||
vm.LinkButtonEnabled = false;
|
||||
DataInstance selectedInstance = vm.SelectedInstance;
|
||||
|
||||
|
||||
var prompt = MessageBox.Show($"Creating hard links from {selectedInstance.InstanceName}.\nProceed to link target selection?", "Make hard links", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
@@ -37,40 +34,77 @@ namespace WPFLinkTool
|
||||
FolderBrowserDialog dialog = new();
|
||||
if (dialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string target = dialog.SelectedPath;
|
||||
|
||||
var uniqueFolders = (from folders in selectedInstance.InstanceFiles
|
||||
where folders.Location != string.Empty
|
||||
select folders.Location).Distinct();
|
||||
|
||||
double progressStep = 100D / (selectedInstance.InstanceFiles.Count + uniqueFolders.Count());
|
||||
|
||||
foreach (var folder in uniqueFolders)
|
||||
{
|
||||
if (!Directory.Exists(target + folder))
|
||||
{
|
||||
await Task.Run(() => Directory.CreateDirectory(target + folder));
|
||||
}
|
||||
vm.Progress += progressStep;
|
||||
}
|
||||
target = dialog.SelectedPath;
|
||||
|
||||
foreach (var file in selectedInstance.InstanceFiles)
|
||||
{
|
||||
if (!File.Exists(target + file.Location + @"\" + file.OriginalFileName))
|
||||
if (File.Exists(target + file.Location + @"\" + file.OriginalFileName))
|
||||
{
|
||||
await Task.Run(() => CreateHardLink(target + file.Location + @"\" + file.OriginalFileName,
|
||||
dbDir + @"\" + file.HashedFileName, IntPtr.Zero));
|
||||
var prompt2 = MessageBox.Show(@$"{file.Location}\{file.OriginalFileName} already exists in the target directory!" + "\n"
|
||||
+ "Do you want to delete all encountered dupes before making hard links? (If you didn't know or forgot, overwriting hard linked files changes the originals) 'No' cancels the whole operation.", "Duplicate files detected!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||
|
||||
if (prompt2 == DialogResult.Yes)
|
||||
{
|
||||
proceed = true;
|
||||
delet = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
proceed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (delet)
|
||||
{
|
||||
foreach (var file in selectedInstance.InstanceFiles)
|
||||
{
|
||||
if (File.Exists(target + file.Location + @"\" + file.OriginalFileName))
|
||||
{
|
||||
File.Delete(target + file.Location + @"\" + file.OriginalFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (proceed)
|
||||
{
|
||||
var uniqueFolders = (from folders in selectedInstance.InstanceFiles
|
||||
where folders.Location != string.Empty
|
||||
select folders.Location).Distinct();
|
||||
|
||||
double progressStep = 100D / (selectedInstance.InstanceFiles.Count + uniqueFolders.Count());
|
||||
|
||||
foreach (var folder in uniqueFolders)
|
||||
{
|
||||
if (!Directory.Exists(target + folder))
|
||||
{
|
||||
await Task.Run(() => Directory.CreateDirectory(target + folder));
|
||||
}
|
||||
vm.Progress += progressStep;
|
||||
}
|
||||
|
||||
foreach (var file in selectedInstance.InstanceFiles)
|
||||
{
|
||||
if (!File.Exists(target + file.Location + @"\" + file.OriginalFileName))
|
||||
{
|
||||
await Task.Run(() => CreateHardLink(target + file.Location + @"\" + file.OriginalFileName,
|
||||
dbDir + @"\" + file.HashedFileName, IntPtr.Zero));
|
||||
}
|
||||
vm.Progress += progressStep;
|
||||
}
|
||||
vm.Progress += progressStep;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
vm.Progress = 0;
|
||||
|
||||
|
||||
|
||||
vm.UIEnabled = true;
|
||||
vm.LinkButtonEnabled = true;
|
||||
IsExecuting = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ namespace WPFLinkTool
|
||||
{
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
public readonly SharedViewModel Shared;
|
||||
public SharedViewModel Shared;
|
||||
|
||||
private string _dBSize;
|
||||
public string DBSize
|
||||
{
|
||||
@@ -95,8 +96,8 @@ namespace WPFLinkTool
|
||||
OnPropertyChanged(nameof(HeaderText));
|
||||
}
|
||||
}
|
||||
private string _selectedInstance;
|
||||
public string SelectedInstance
|
||||
private DataInstance _selectedInstance;
|
||||
public DataInstance SelectedInstance
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -106,6 +107,7 @@ namespace WPFLinkTool
|
||||
{
|
||||
_selectedInstance = value;
|
||||
OnPropertyChanged(nameof(SelectedInstance));
|
||||
LinkButtonEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +123,7 @@ namespace WPFLinkTool
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public RelayCommand OpenAddInstanceWindow { get; private set; }
|
||||
public RelayCommand SelectedInstanceCommand { get; private set; }
|
||||
public RelayCommand DeleteInstanceCommand { get; private set; }
|
||||
@@ -133,7 +136,6 @@ namespace WPFLinkTool
|
||||
Directory.CreateDirectory(dbDir);
|
||||
Shared = shared;
|
||||
OpenAddInstanceWindow = new(OpenInstanceWindow);
|
||||
SelectedInstanceCommand = new(SetSelectedRadioButton);
|
||||
DeleteInstanceCommand = new(DeleteInstance);
|
||||
MakeHardLinksCommand = new MakeHardLinksCommand(this, (ex) => HeaderText = ex.Message);
|
||||
DeleteUnusedCommand = new DeleteUnusedCommand(this, (ex) => HeaderText = ex.Message);
|
||||
@@ -165,24 +167,14 @@ namespace WPFLinkTool
|
||||
LinkButtonEnabled = false;
|
||||
Task.Run(() => UpdateDBSize());
|
||||
Task.Run(() => UpdateSumSize());
|
||||
}
|
||||
|
||||
public void SetSelectedRadioButton(object o)
|
||||
{
|
||||
SelectedInstance = (string)o;
|
||||
LinkButtonEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteInstance(object o)
|
||||
{
|
||||
var prompt = MessageBox.Show($"Delete {SelectedInstance}?", "Delete instance", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
var prompt = MessageBox.Show($"Delete {SelectedInstance.InstanceName}?", "Delete instance", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
if (prompt == DialogResult.Yes)
|
||||
{
|
||||
DataInstance selected = (from inst in Shared.Info.InstanceList
|
||||
where inst.InstanceName == SelectedInstance
|
||||
select inst).Single();
|
||||
|
||||
Shared.Info.InstanceList.Remove(selected);
|
||||
Shared.Info.InstanceList.Remove(SelectedInstance);
|
||||
Shared.Info.SaveToXml();
|
||||
LinkButtonEnabled = false;
|
||||
UpdateSumSize();
|
||||
|
||||
@@ -8,16 +8,13 @@ namespace WPFLinkTool
|
||||
{
|
||||
public class SharedViewModel : ViewModelBase
|
||||
{
|
||||
private DBInfo _info;
|
||||
private DBInfo _Info;
|
||||
public DBInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return _info;
|
||||
}
|
||||
get { return _Info; }
|
||||
set
|
||||
{
|
||||
_info = value;
|
||||
_Info = value;
|
||||
OnPropertyChanged(nameof(Info));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>otoge.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="otoge.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
Reference in New Issue
Block a user