using System; using System.IO; using System.Windows.Controls; using System.Windows; using System.Collections.Generic; using System.Linq; namespace TapeCatalog.Methods { // Reusable helper methods for copy-related UI functionality public static class Copy { // guard to prevent recursive Checked/Unchecked handling while we programmatically change states private static bool _suppressCheckEvents = false; public static void PopulateTree(TreeView tree, string path) { if (tree == null) return; tree.Items.Clear(); if (string.IsNullOrWhiteSpace(path) || !Directory.Exists(path)) return; var rootDir = new DirectoryInfo(path); var rootItem = CreateDirectoryNode(rootDir); rootItem.IsExpanded = true; tree.Items.Add(rootItem); } public static TreeViewItem CreateDirectoryNode(DirectoryInfo dir) { var item = new TreeViewItem { Tag = dir.FullName }; // Create header with a checkbox for the directory as well var headerPanel = new StackPanel { Orientation = Orientation.Horizontal }; var dirCb = new CheckBox { VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 4, 0) }; var dirTb = new TextBlock { Text = dir.Name, VerticalAlignment = VerticalAlignment.Center }; headerPanel.Children.Add(dirCb); headerPanel.Children.Add(dirTb); item.Header = headerPanel; try { // add subdirectories foreach (var sub in dir.GetDirectories()) { item.Items.Add(CreateDirectoryNode(sub)); } // add files foreach (var f in dir.GetFiles()) { var fileItem = new TreeViewItem { Tag = f.FullName }; var sp = new StackPanel { Orientation = Orientation.Horizontal }; var cb = new CheckBox { VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 4, 0) }; var tb = new TextBlock { Text = f.Name, VerticalAlignment = VerticalAlignment.Center }; sp.Children.Add(cb); sp.Children.Add(tb); fileItem.Header = sp; item.Items.Add(fileItem); } } catch { // ignore access exceptions } // Wire events to propagate state to children when directory checkbox is toggled dirCb.Checked += (s, e) => { if (_suppressCheckEvents) return; try { _suppressCheckEvents = true; SetCheckedState(item, true); } finally { _suppressCheckEvents = false; } }; dirCb.Unchecked += (s, e) => { if (_suppressCheckEvents) return; try { _suppressCheckEvents = true; SetCheckedState(item, false); } finally { _suppressCheckEvents = false; } }; return item; } private static void SetCheckedState(TreeViewItem node, bool isChecked) { foreach (var it in node.Items) { if (it is TreeViewItem child) { // child header expected to be a StackPanel with a CheckBox as first child if (child.Header is StackPanel sp && sp.Children.Count > 0) { foreach (var ch in sp.Children) { if (ch is CheckBox childCb) { childCb.IsChecked = isChecked; break; } } } // recurse into grandchildren if (child.Items != null && child.Items.Count > 0) { SetCheckedState(child, isChecked); } } } } // Collect checked files and copy them to archive preserving relative folders public static Tuple CopySelectedToArchive(TreeView tree, string sourceRoot, string archivePath) { if (tree == null) return Tuple.Create(0, 0); var files = new List(); foreach (var it in tree.Items) { if (it is TreeViewItem tvi) CollectCheckedFiles(tvi, files); } int copied = 0, failed = 0; foreach (var src in files) { try { var fileDir = System.IO.Path.GetDirectoryName(src) ?? string.Empty; string relative; if (!string.IsNullOrWhiteSpace(sourceRoot) && fileDir.StartsWith(sourceRoot, StringComparison.OrdinalIgnoreCase)) relative = fileDir.Substring(sourceRoot.Length).TrimStart(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar); else relative = System.IO.Path.GetFileName(fileDir); var destDir = System.IO.Path.Combine(archivePath, relative); Directory.CreateDirectory(destDir); var destFile = System.IO.Path.Combine(destDir, System.IO.Path.GetFileName(src)); File.Copy(src, destFile, true); copied++; } catch { failed++; } } return Tuple.Create(copied, failed); } // Return a list of all checked file paths in the tree public static List GetCheckedFiles(TreeView tree) { var files = new List(); if (tree == null) return files; foreach (var it in tree.Items) { if (it is TreeViewItem tvi) CollectCheckedFiles(tvi, files); } return files; } private static void CollectCheckedFiles(TreeViewItem node, List list) { if (node.Header is StackPanel sp) { foreach (var child in sp.Children) { if (child is CheckBox cb && cb.IsChecked == true) { if (node.Tag is string path && File.Exists(path)) { list.Add(path); } break; } } } foreach (var it in node.Items) { if (it is TreeViewItem t) CollectCheckedFiles(t, list); } } } }