using System; using System.Windows.Forms; using System.Collections.Generic; using System.Linq; namespace Hawkeye.VisionBuilder.Features.ImageStatistics { public partial class ImageStatisticsDialog : Form { private TreeNode _goodNode; private TreeNode _badNode; private HashSet _allFiles = new HashSet(StringComparer.OrdinalIgnoreCase); private TreeNode? _selectedLeafNode = null; private Dictionary _badDefectCounts = new(StringComparer.OrdinalIgnoreCase); public event Action? FileSelected; public ImageStatisticsDialog() { InitializeComponent(); InitializeTree(); treeView.AfterSelect += treeView_AfterSelect; UpdateNavigationButtons(); } private void InitializeTree() { treeView.Nodes.Clear(); _goodNode = new TreeNode(GetBranchText("Good", 0)); _badNode = new TreeNode(GetBranchText("Bad", 0)); treeView.Nodes.Add(_goodNode); treeView.Nodes.Add(_badNode); treeView.ExpandAll(); _allFiles.Clear(); _badDefectCounts.Clear(); } public void AddGoodImage(string filePath) { if (_allFiles.Contains(filePath)) return; string nodeText = System.IO.Path.GetFileName(filePath); _goodNode.Nodes.Add(new TreeNode(nodeText) { Tag = filePath }); _allFiles.Add(filePath); UpdateBranchText(_goodNode, "Good"); //treeView.ExpandAll(); } public void AddBadImage(string filePath, string[]? defects = null) { if (_allFiles.Contains(filePath)) return; string nodeText = System.IO.Path.GetFileName(filePath); if (defects != null && defects.Length > 0) { nodeText += " (" + string.Join(", ", defects) + ")"; foreach (var defect in defects) { if (string.IsNullOrWhiteSpace(defect)) continue; if (_badDefectCounts.ContainsKey(defect)) _badDefectCounts[defect]++; else _badDefectCounts[defect] = 1; } } _badNode.Nodes.Add(new TreeNode(nodeText) { Tag = filePath }); _allFiles.Add(filePath); UpdateBranchText(_badNode, "Bad"); //treeView.ExpandAll(); } public void AddExpected(string filePath, string[]? defects) { // get folder name as expected defect string expectedDefect = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(filePath) ?? string.Empty) ?? string.Empty; if (defects.Contains(expectedDefect, StringComparer.OrdinalIgnoreCase)) { AddGoodImage(filePath); } else { AddBadImage(filePath, [expectedDefect]); } } private void UpdateBranchText(TreeNode node, string name) { if (node == _badNode) { node.Text = GetBranchText(name, node.Nodes.Count); } else { node.Text = GetBranchText(name, node.Nodes.Count); } } private string GetBranchText(string name, int count) { if (name == "Bad") { if (_badDefectCounts.Count > 0) { var defectSummary = string.Join(", ", _badDefectCounts .OrderByDescending(kv => kv.Value) .ThenBy(kv => kv.Key) .Select(kv => $"{kv.Key} {kv.Value}") ); return $"{name} ({defectSummary})"; } } return $"{name} ({count})"; } private void btnReset_Click(object sender, EventArgs e) { InitializeTree(); _badDefectCounts.Clear(); } private void btnClose_Click(object sender, EventArgs e) { this.Close(); } private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) { // Only fire event for leaf nodes (filenames) if (e.Node.Parent != null && e.Node.Tag is string filePath) { _selectedLeafNode = e.Node; FileSelected?.Invoke(filePath); } else { _selectedLeafNode = null; } UpdateNavigationButtons(); } private void treeView_AfterSelect(object? sender, TreeViewEventArgs e) { // Only consider leaf nodes (filenames) if (e.Node.Parent != null && e.Node.Tag is string) { _selectedLeafNode = e.Node; } else { _selectedLeafNode = null; } UpdateNavigationButtons(); } private void UpdateNavigationButtons() { if (_selectedLeafNode == null) { btnBackward.Enabled = false; btnForward.Enabled = false; return; } var parent = _selectedLeafNode.Parent; if (parent == null) { btnBackward.Enabled = false; btnForward.Enabled = false; return; } int idx = parent.Nodes.IndexOf(_selectedLeafNode); btnBackward.Enabled = idx > 0; btnForward.Enabled = idx < parent.Nodes.Count - 1; } private void btnBackward_Click(object sender, EventArgs e) { if (_selectedLeafNode == null) return; var parent = _selectedLeafNode.Parent; if (parent == null) return; int idx = parent.Nodes.IndexOf(_selectedLeafNode); if (idx > 0) { var prev = parent.Nodes[idx - 1]; treeView.SelectedNode = prev; treeView.Focus(); if (prev.Tag is string filePath) FileSelected?.Invoke(filePath); } } private void btnForward_Click(object sender, EventArgs e) { if (_selectedLeafNode == null) return; var parent = _selectedLeafNode.Parent; if (parent == null) return; int idx = parent.Nodes.IndexOf(_selectedLeafNode); if (idx < parent.Nodes.Count - 1) { var next = parent.Nodes[idx + 1]; treeView.SelectedNode = next; treeView.Focus(); if (next.Tag is string filePath) FileSelected?.Invoke(filePath); } } } }