Added a copy button to modal window for easier bug fixing

This commit is contained in:
Frederik Jacobsen 2025-10-18 23:14:52 +02:00
parent 589495911d
commit d1aae545e9
2 changed files with 79 additions and 13 deletions

View File

@ -186,13 +186,40 @@ public partial class LeftTreeView : UserControl
// Compose content // Compose content
if (dialog.Content is Grid grid) if (dialog.Content is Grid grid)
{ {
var textBlock = new TextBlock // Use a read-only TextBox so users can select text easily
var textBox = new TextBox
{ {
Text = text, Text = text,
IsReadOnly = true,
AcceptsReturn = true,
TextWrapping = Avalonia.Media.TextWrapping.Wrap, TextWrapping = Avalonia.Media.TextWrapping.Wrap,
Margin = new Thickness(12) Margin = new Thickness(12)
}; };
var scroller = new ScrollViewer { Content = textBlock };
var scroller = new ScrollViewer { Content = textBox };
// Copy button
var copyButton = new Button
{
Content = "Copy",
MinWidth = 80,
HorizontalAlignment = HorizontalAlignment.Right,
Margin = new Thickness(8)
};
copyButton.Click += async (_, _) =>
{
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel?.Clipboard != null)
{
await topLevel.Clipboard.SetTextAsync(text);
// Provide lightweight feedback by changing content briefly
if (copyButton.Content is string)
copyButton.Content = "Copied";
await Task.Delay(1000);
if (copyButton.Content is string)
copyButton.Content = "Copy";
}
};
var closeButton = new Button var closeButton = new Button
{ {
@ -208,6 +235,7 @@ public partial class LeftTreeView : UserControl
Orientation = Orientation.Horizontal, Orientation = Orientation.Horizontal,
HorizontalAlignment = HorizontalAlignment.Right HorizontalAlignment = HorizontalAlignment.Right
}; };
buttonsPanel.Children.Add(copyButton);
buttonsPanel.Children.Add(closeButton); buttonsPanel.Children.Add(closeButton);
Grid.SetRow(buttonsPanel, 1); Grid.SetRow(buttonsPanel, 1);

View File

@ -18,15 +18,7 @@ public static class XmlValidator
{ {
var result = new XmlValidationResult(); var result = new XmlValidationResult();
// Ensure the requested element exists in the schema set // Probe XML root element first, we may use its namespace as a hint
var qname = new XmlQualifiedName(elementName, elementNamespace ?? string.Empty);
if (schemas.GlobalElements[qname] is not XmlSchemaElement)
{
result.AddError($"Element '{qname}' was not found in the compiled schema set.");
return result;
}
// Probe XML root element
(string localName, string nsUri)? rootInfo = TryReadRoot(xmlPath); (string localName, string nsUri)? rootInfo = TryReadRoot(xmlPath);
if (rootInfo is null) if (rootInfo is null)
{ {
@ -35,6 +27,42 @@ public static class XmlValidator
} }
var (rootLocal, rootNs) = rootInfo.Value; var (rootLocal, rootNs) = rootInfo.Value;
// Try to ensure the requested element exists in the schema set; if not, try to infer the correct namespace instead of failing hard.
var qname = new XmlQualifiedName(elementName, elementNamespace ?? string.Empty);
if (schemas.GlobalElements[qname] is not XmlSchemaElement)
{
// Try to find candidates with the same local name across namespaces
var candidates = schemas.GlobalElements.Names.Cast<XmlQualifiedName>().Where(n => string.Equals(n.Name, elementName, StringComparison.Ordinal)).Distinct().ToList();
if (candidates.Count == 1)
{
elementNamespace = candidates[0].Namespace;
qname = new XmlQualifiedName(elementName, elementNamespace ?? string.Empty);
result.AddWarning($"Element '{{{qname.Namespace}}}{qname.Name}' was not found with the provided namespace. Using detected namespace '{candidates[0].Namespace}'.");
}
else if (candidates.Count > 1)
{
// Prefer a candidate matching the XML root namespace if any
var preferred = candidates.FirstOrDefault(c => string.Equals(c.Namespace ?? string.Empty, rootNs ?? string.Empty, StringComparison.Ordinal));
if (preferred != null)
{
elementNamespace = preferred.Namespace;
qname = new XmlQualifiedName(elementName, elementNamespace ?? string.Empty);
result.AddWarning($"Element namespace adjusted to match XML root namespace: '{{{preferred.Namespace}}}{preferred.Name}'.");
}
else
{
var list = string.Join(", ", candidates.Select(c => $"'{{{c.Namespace}}}{c.Name}'"));
result.AddWarning($"Element '{{{qname.Namespace}}}{qname.Name}' was not found in the compiled schema set. Candidates by name: {list}. Proceeding with best-effort validation.");
}
}
else
{
// No candidates at all; continue and let the validator report more actionable errors.
result.AddWarning($"Element '{{{qname.Namespace}}}{qname.Name}' was not found in the compiled schema set. Proceeding with best-effort validation.");
}
}
var matchesRoot = string.Equals(rootLocal, elementName, StringComparison.Ordinal) && string.Equals(rootNs ?? string.Empty, elementNamespace ?? string.Empty, StringComparison.Ordinal); var matchesRoot = string.Equals(rootLocal, elementName, StringComparison.Ordinal) && string.Equals(rootNs ?? string.Empty, elementNamespace ?? string.Empty, StringComparison.Ordinal);
var settings = new XmlReaderSettings var settings = new XmlReaderSettings
@ -99,8 +127,18 @@ public static class XmlValidator
if (elementNode is null) if (elementNode is null)
{ {
result.AddError($"Could not find any element '{{{elementNamespace}}}{elementName}' in the XML document to validate against."); // Try again ignoring namespace, in case the provided namespace was incorrect or omitted
return result; var retry = FindFirstElementNode(xmlPath, elementName, null).Node;
if (retry is not null)
{
result.AddWarning($"Could not find element '{{{elementNamespace}}}{elementName}' with the specified namespace; validating first occurrence by local name only.");
elementNode = retry;
}
else
{
result.AddError($"Could not find any element '{{{elementNamespace}}}{elementName}' in the XML document to validate against.");
return result;
}
} }
// Inform as a warning that we validate a subtree instead of the document root // Inform as a warning that we validate a subtree instead of the document root