using System; using System.Collections.Generic; using System.Globalization; using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Utility.Raii; using Dalamud.Plugin; using Questionable.Data; using Questionable.Validation; namespace Questionable.Windows.QuestComponents; internal sealed class QuestValidationComponent { private readonly QuestValidator _questValidator; private readonly QuestData _questData; private readonly IDalamudPluginInterface _pluginInterface; private readonly ValidationDetailsRenderer _detailsRenderer; public bool ShouldDraw => _questValidator.Issues.Count > 0; public QuestValidationComponent(QuestValidator questValidator, QuestData questData, IDalamudPluginInterface pluginInterface) { _questValidator = questValidator; _questData = questData; _pluginInterface = pluginInterface; _detailsRenderer = new ValidationDetailsRenderer(questData, pluginInterface); } public void Draw() { DrawSummaryHeader(); ImGui.Separator(); DrawValidationTable(); _detailsRenderer.DrawDetailWindows(); } private void DrawSummaryHeader() { int issueCount = _questValidator.IssueCount; int errorCount = _questValidator.ErrorCount; int num = issueCount - errorCount; ImU8String text = new ImU8String(33, 1); text.AppendLiteral("Validation Results: "); text.AppendFormatted(issueCount); text.AppendLiteral(" total issues"); ImGui.Text(text); if (errorCount > 0) { ImGui.SameLine(); ImGui.Text("("); ImGui.SameLine(); using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed)) { text = new ImU8String(7, 1); text.AppendFormatted(errorCount); text.AppendLiteral(" errors"); ImGui.Text(text); } } if (num > 0) { if (errorCount > 0) { ImGui.SameLine(); using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange)) { text = new ImU8String(12, 1); text.AppendLiteral(", "); text.AppendFormatted(num); text.AppendLiteral(" warnings)"); ImGui.Text(text); return; } } ImGui.SameLine(); ImGui.Text("("); ImGui.SameLine(); using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange)) { text = new ImU8String(10, 1); text.AppendFormatted(num); text.AppendLiteral(" warnings)"); ImGui.Text(text); return; } } if (errorCount > 0) { ImGui.SameLine(); ImGui.Text(")"); } } private void DrawValidationTable() { using ImRaii.IEndObject endObject = ImRaii.Table("ValidationIssues", 6, ImGuiTableFlags.Borders | ImGuiTableFlags.Sortable | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY); if (!(!endObject)) { ImGui.TableSetupColumn("ID", ImGuiTableColumnFlags.WidthFixed, 60f); ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, 250f); ImGui.TableSetupColumn("Seq", ImGuiTableColumnFlags.WidthFixed, 40f); ImGui.TableSetupColumn("Step", ImGuiTableColumnFlags.WidthFixed, 40f); ImGui.TableSetupColumn("Issue", ImGuiTableColumnFlags.WidthStretch); ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 60f); ImGui.TableHeadersRow(); IReadOnlyList issues = _questValidator.Issues; for (int i = 0; i < issues.Count; i++) { DrawValidationRow(issues[i], i); } } } private void DrawValidationRow(ValidationIssue issue, int index) { ImGui.TableNextRow(); if (ImGui.TableNextColumn()) { ImGui.TextUnformatted(issue.ElementId?.ToString() ?? string.Empty); } if (ImGui.TableNextColumn()) { ImGui.TextUnformatted((issue.ElementId != null) ? _questData.GetQuestInfo(issue.ElementId).Name : issue.AlliedSociety.ToString()); } if (ImGui.TableNextColumn()) { if (issue.Sequence.HasValue) { ImGui.TextUnformatted(issue.Sequence.Value.ToString(CultureInfo.InvariantCulture)); } else { using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey2)) { ImGui.TextUnformatted("\ufffd"); } } } if (ImGui.TableNextColumn()) { if (issue.Step.HasValue) { ImGui.TextUnformatted(issue.Step.Value.ToString(CultureInfo.InvariantCulture)); } else { using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey2)) { ImGui.TextUnformatted("\ufffd"); } } } if (ImGui.TableNextColumn()) { DrawIssueCell(issue, index); } if (ImGui.TableNextColumn()) { DrawActionsCell(issue, index); } } private void DrawIssueCell(ValidationIssue issue, int index) { Vector4 color = ((issue.Severity == EIssueSeverity.Error) ? ImGuiColors.DalamudRed : ImGuiColors.DalamudOrange); FontAwesomeIcon icon = ((issue.Severity == EIssueSeverity.Error) ? FontAwesomeIcon.ExclamationTriangle : FontAwesomeIcon.InfoCircle); using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push()) { using (ImRaii.PushColor(ImGuiCol.Text, color)) { ImGui.TextUnformatted(icon.ToIconString()); } } ImGui.SameLine(); string issueSummary = GetIssueSummary(issue); using (ImRaii.PushColor(ImGuiCol.Text, color)) { ImGui.TextWrapped(issueSummary); } } private void DrawActionsCell(ValidationIssue issue, int index) { if (HasDetailedDescription(issue) && ImGui.SmallButton($"Details##{index}")) { _detailsRenderer.OpenDetails(issue, index); } } private static string GetIssueSummary(ValidationIssue issue) { string text = ValidationDetailsRenderer.CleanJsonText(issue.Description ?? string.Empty); if (issue.Type == EIssueType.QuestDisabled && issue.ElementId == null) { string[] array = text.Split(':', 2); if (array.Length == 0) { return text; } return array[0]; } if (issue.Type == EIssueType.InvalidJsonSchema) { string[] array2 = text.Split('\n', 2, StringSplitOptions.RemoveEmptyEntries); if (array2.Length == 0) { return text; } return array2[0]; } if (issue.Type == EIssueType.InvalidJsonSyntax) { string[] array3 = text.Split('\n', 2, StringSplitOptions.RemoveEmptyEntries); if (array3.Length == 0) { return text; } return array3[0]; } string[] array4 = text.Split('\n', StringSplitOptions.RemoveEmptyEntries); if (array4.Length <= 2) { return text; } return array4[0] + ((array4.Length > 1) ? "..." : ""); } private static bool HasDetailedDescription(ValidationIssue issue) { string text = issue.Description ?? string.Empty; if (issue.Type == EIssueType.QuestDisabled && issue.ElementId == null) { return true; } if (issue.Type == EIssueType.InvalidJsonSchema) { return true; } if (issue.Type == EIssueType.InvalidJsonSyntax) { return true; } if (!text.Contains('\n', StringComparison.Ordinal)) { return text.Length > 100; } return true; } }