SHA256
Update UI
This commit is contained in:
1 parent
abab3612f2
commit
a3b41679c9
6 files changed
+417
-315
No files matched your search
+185
@@ -0,0 +1,185 @@
|
||||
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<int,int> CopySelectedToArchive(TreeView tree, string sourceRoot, string archivePath)
|
||||
{
|
||||
if (tree == null) return Tuple.Create(0, 0);
|
||||
var files = new List<string>();
|
||||
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<string> GetCheckedFiles(TreeView tree)
|
||||
{
|
||||
var files = new List<string>();
|
||||
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<string> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
|
||||
namespace TapeCatalog.Methods
|
||||
{
|
||||
// Reusable helper methods for copy-related UI functionality
|
||||
public static class CopyMethods
|
||||
{
|
||||
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 { Header = dir.Name, Tag = dir.FullName };
|
||||
try
|
||||
{
|
||||
foreach (var sub in dir.GetDirectories())
|
||||
{
|
||||
item.Items.Add(CreateDirectoryNode(sub));
|
||||
}
|
||||
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
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace TapeCatalog.Methods
|
||||
{
|
||||
/// <summary>
|
||||
/// Helpers to read XML files and produce a compact summary used by the UI.
|
||||
/// </summary>
|
||||
public static class Xml
|
||||
{
|
||||
public static List<TapeCatalog.FileEntry> ParseSummary(string filePath)
|
||||
{
|
||||
var result = new List<TapeCatalog.FileEntry>();
|
||||
if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
|
||||
return result;
|
||||
|
||||
try
|
||||
{
|
||||
var doc = XDocument.Load(filePath);
|
||||
var root = doc.Root;
|
||||
if (root == null) return result;
|
||||
|
||||
if (string.Equals(root.Name.LocalName, "Files", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var fe in root.Elements("File"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var fn = fe.Element("Filename")?.Value ?? string.Empty;
|
||||
var fd = fe.Element("FileDir")?.Value ?? string.Empty;
|
||||
var st = fe.Element("Status")?.Value ?? string.Empty;
|
||||
result.Add(new TapeCatalog.FileEntry { Filename = fn, FileDir = fd, Status = st });
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore malformed entries
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (string.Equals(root.Name.LocalName, "TapeEntries", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var entry in root.Elements("Entry"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var fn = entry.Element("Filename")?.Value ?? string.Empty;
|
||||
var med = entry.Element("Medium")?.Value ?? string.Empty;
|
||||
var mod = entry.Element("Modified")?.Value ?? string.Empty;
|
||||
result.Add(new TapeCatalog.FileEntry { Filename = fn, FileDir = med, Status = mod });
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore malformed entries
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore parse errors and return empty list
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string[] GetXmlFiles(string xmlDirectory)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(xmlDirectory) || !Directory.Exists(xmlDirectory))
|
||||
return Array.Empty<string>();
|
||||
|
||||
try
|
||||
{
|
||||
return Directory.GetFiles(xmlDirectory, "*.xml", SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user