refactor: Relocate Document, BinFileSaver, and Toolbox to proper folders

- Move Document.cs from Forms to Models namespace
- Move BinFileSaver.cs and Toolbox.cs from Forms to Services namespace
- Better separation of concerns between UI and business logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-30 08:07:37 -05:00
parent 4f6854baf8
commit 9abda896ea
4 changed files with 137 additions and 198 deletions
+131
View File
@@ -0,0 +1,131 @@
using CutList.Core;
using CutList.Core.Formatting;
using System.Diagnostics;
namespace CutList.Services
{
public class BinFileSaver
{
private readonly IEnumerable<Bin> _bins;
private int PaddingWidthOfItemLength { get; set; }
public bool OpenFileAfterSave { get; set; }
public BinFileSaver(IEnumerable<Bin> bins)
{
_bins = bins ?? throw new ArgumentNullException(nameof(bins));
}
public void SaveBinsToFile(string file)
{
using (var writer = new StreamWriter(file))
{
writer.AutoFlush = true;
PaddingWidthOfItemLength = _bins
.SelectMany(b => b.Items)
.Select(i => FormatHelper.ConvertToMixedFraction(i.Length).Length)
.DefaultIfEmpty(0)
.Max();
WriteHeader(writer);
var id = 1;
foreach (var bin in _bins)
{
WriteBinSummary(writer, bin, id++);
}
WriteFinalSummary(writer);
}
if (OpenFileAfterSave)
{
OpenFile(file);
}
}
private void OpenFile(string file)
{
try
{
Process.Start("notepad.exe", file);
}
catch
{
Process.Start(file);
}
}
private void WriteHeader(StreamWriter writer)
{
var totalBars = _bins.Count();
var totalItems = _bins.Sum(b => b.Items.Count);
writer.WriteLine("CUT LIST");
writer.WriteLine($"Date: {DateTime.Now:g}");
writer.WriteLine($"Total stock bars needed: {totalBars}");
writer.WriteLine($"Total pieces to cut: {totalItems}");
writer.WriteLine();
}
private void WriteBinSummary(StreamWriter writer, Bin bin, int id)
{
var stockLength = FormatHelper.ConvertToMixedFraction(bin.Length);
var dropLength = FormatHelper.ConvertToMixedFraction(bin.RemainingLength);
writer.WriteLine(new string('─', 50));
writer.WriteLine($"BAR #{id} - Start with {stockLength}\" stock");
writer.WriteLine();
writer.WriteLine(" Cut these pieces:");
WriteBinItems(writer, bin);
writer.WriteLine();
writer.WriteLine($" Remaining drop: {dropLength}\"");
writer.WriteLine();
}
private void WriteBinItems(StreamWriter writer, Bin bin)
{
var groups = bin.Items
.GroupBy(i => new { i.Name, i.Length })
.OrderBy(g => g.Key.Name)
.ThenBy(g => g.Key.Length);
var lengthHeader = "LENGTH".PadLeft(PaddingWidthOfItemLength + 1);
writer.WriteLine($" QTY {lengthHeader} LABEL");
foreach (var group in groups)
{
var first = group.First();
var count = group.Count();
var length = FormatHelper
.ConvertToMixedFraction(first.Length)
.PadLeft(PaddingWidthOfItemLength) + "\"";
writer.WriteLine($" {count,3} {length} {first.Name}");
}
}
private void WriteFinalSummary(StreamWriter writer)
{
var totalBars = _bins.Count();
var totalItems = _bins.Sum(b => b.Items.Count);
var totalStock = _bins.Sum(b => b.Length);
var totalDrop = _bins.Sum(b => b.RemainingLength);
string fmt(double v) => FormatHelper.ConvertToMixedFraction(v);
writer.WriteLine(new string('═', 50));
writer.WriteLine("SUMMARY");
writer.WriteLine($" Stock bars needed: {totalBars}");
writer.WriteLine($" Total pieces to cut: {totalItems}");
writer.WriteLine($" Total material used: {fmt(totalStock)}\"");
writer.WriteLine($" Total drop/waste: {fmt(totalDrop)}\"");
writer.WriteLine(new string('═', 50));
}
}
}
+54
View File
@@ -0,0 +1,54 @@
using Newtonsoft.Json;
namespace CutList.Services
{
public class Toolbox
{
public Toolbox()
{
Load();
}
public List<Tool> Tools { get; set; }
public string ToolsFilePath { get; set; } = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data\\Tools.json");
private void LoadDefaultTools()
{
Tools = new List<Tool>
{
new Tool { Name = "Shear", Kerf = 0.0 },
new Tool { Name = "Saw", Kerf = 0.125 },
new Tool { Name = "Channel Muncher", Kerf = 0.5 },
new Tool { Name = "Custom", Kerf = 1, AllowUserToChange = true }
};
}
/// <summary>
/// Loads the tool list from the file at ToolsFilePath
/// </summary>
public void Load()
{
if (!File.Exists(ToolsFilePath))
{
LoadDefaultTools();
Save();
}
else
{
var json = File.ReadAllText(ToolsFilePath);
var list = JsonConvert.DeserializeObject<List<Tool>>(json);
Tools = list;
}
}
public void Save()
{
if (Tools == null)
return;
var json = JsonConvert.SerializeObject(Tools, Formatting.Indented);
File.WriteAllText(ToolsFilePath, json);
}
}
}