using System.Globalization; using System.Text; using Avalonia; using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.VisualTree; using XSDVisualiser.Models; namespace XSDVisualiser.Desktop.Views { public partial class LeftTreeView : UserControl { public LeftTreeView() { InitializeComponent(); } private async void OnCopyAsTsvClick(object? sender, RoutedEventArgs e) { // Determine the node from the menu item's DataContext var node = (sender as MenuItem)?.DataContext as SchemaNode; if (node == null) node = (sender as Control)?.GetVisualAncestors().OfType().FirstOrDefault()?.DataContext as SchemaNode; if (node == null) return; var tsv = BuildTsv(node); var topLevel = TopLevel.GetTopLevel(this); if (topLevel?.Clipboard != null) { await topLevel.Clipboard.SetTextAsync(tsv); } } private static string BuildTsv(SchemaNode root) { var sb = new StringBuilder(); // Header sb.AppendLine("Depth\tPath\tName\tNamespace\tTypeName\tBuiltInType\tMinOccurs\tMaxOccurs\tContentModel\tIsNillable"); var initialPath = root.Name ?? string.Empty; AppendNode(sb, root, 0, initialPath); return sb.ToString(); } private static void AppendNode(StringBuilder sb, SchemaNode node, int depth, string path) { string San(string? s) { if (string.IsNullOrEmpty(s)) return string.Empty; return s.Replace("\t", " ").Replace("\r", " ").Replace("\n", " "); } var min = node.Cardinality?.Min.ToString(CultureInfo.InvariantCulture) ?? string.Empty; string max; if (node.Cardinality?.MaxIsUnbounded == true) max = "unbounded"; else max = node.Cardinality != null ? node.Cardinality.Max.ToString(CultureInfo.InvariantCulture) : string.Empty; var line = string.Join("\t", new[] { depth.ToString(CultureInfo.InvariantCulture), San(path), San(node.Name), San(node.Namespace), San(node.TypeName), San(node.BuiltInType), min, max, San(node.ContentModel), node.IsNillable ? "true" : "false" }); sb.AppendLine(line); if (node.Children != null) { foreach (var child in node.Children) { var nextPathSegment = child.Name ?? string.Empty; var childPath = string.IsNullOrEmpty(San(path)) ? nextPathSegment : $"{path}/{nextPathSegment}"; AppendNode(sb, child, depth + 1, childPath); } } } } }