Validator.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace FastReport.Utils
  8. {
  9. public struct ValidationError
  10. {
  11. public enum ErrorLevel
  12. {
  13. Warning,
  14. Error
  15. }
  16. public string Name;
  17. public ErrorLevel Level;
  18. public string Message;
  19. public ReportComponentBase Object;
  20. public ValidationError(string name, ErrorLevel level, string message, ReportComponentBase obj)
  21. {
  22. this.Name = name;
  23. this.Level = level;
  24. this.Message = message;
  25. this.Object = obj;
  26. }
  27. }
  28. /// <summary>
  29. /// Contains methods used for validation of report.
  30. /// </summary>
  31. public static class Validator
  32. {
  33. internal static void NormalizeBounds(ref RectangleF bounds)
  34. {
  35. if (bounds.Width < 0)
  36. {
  37. bounds.X = bounds.Right;
  38. bounds.Width = -bounds.Width;
  39. }
  40. if (bounds.Height < 0)
  41. {
  42. bounds.Y = bounds.Bottom;
  43. bounds.Height = -bounds.Height;
  44. }
  45. }
  46. internal static void GetIntersectingObjects(List<ReportComponentBase> list, BandBase band)
  47. {
  48. int n = band.Objects.Count;
  49. for (int i = 0; i < n; i++)
  50. {
  51. var bounds = band.Objects[i].Bounds;
  52. if (bounds.Width < 0 || bounds.Height < 0)
  53. NormalizeBounds(ref bounds);
  54. // compensate for inaccuracy of designer's grid fit
  55. bounds.Inflate(-0.01f, -0.01f);
  56. for (int j = 0; j < n; j++)
  57. {
  58. var bounds1 = band.Objects[j].Bounds;
  59. if (bounds1.Width < 0 || bounds1.Height < 0)
  60. NormalizeBounds(ref bounds1);
  61. if (i != j && bounds.IntersectsWith(bounds1))
  62. {
  63. list.Add(band.Objects[i]);
  64. break;
  65. }
  66. }
  67. }
  68. }
  69. internal static bool RectContainInOtherRect(RectangleF parent, RectangleF child)
  70. {
  71. NormalizeBounds(ref parent);
  72. NormalizeBounds(ref child);
  73. // compensate for inaccuracy of designer's grid fit
  74. child.Inflate(-0.01f, -0.01f);
  75. return parent.Contains(child);
  76. }
  77. /// <summary>
  78. /// Validate report.
  79. /// </summary>
  80. /// <param name="report"></param>
  81. /// <param name="checkIntersectObj">Need set false if enabled backlight intersecting objects and report is designing.</param>
  82. /// <param name="token">Token for cancelling method if it execute in thread.</param>
  83. /// <returns>List of errors.</returns>
  84. public static List<ValidationError> ValidateReport(Report report, bool checkIntersectObj = true, CancellationToken token = default)
  85. {
  86. if (report == null)
  87. return null;
  88. List<ValidationError> listError = new List<ValidationError>();
  89. try
  90. {
  91. foreach (PageBase page in report.Pages)
  92. {
  93. foreach (Base c in page.AllObjects)
  94. {
  95. if (token.IsCancellationRequested)
  96. return null;
  97. if (c is BandBase band && checkIntersectObj)
  98. {
  99. List<ReportComponentBase> intersectingObjects = new List<ReportComponentBase>();
  100. GetIntersectingObjects(intersectingObjects, band);
  101. foreach (var obj in intersectingObjects)
  102. {
  103. listError.Add(new ValidationError(obj.Name, ValidationError.ErrorLevel.Warning, Res.Get("Messages,Validator,IntersectedObjects"), obj));
  104. }
  105. }
  106. if (c is ReportComponentBase comp)
  107. listError.AddRange(comp.Validate());
  108. }
  109. }
  110. bool duplicateName;
  111. var objects = report.AllObjects;
  112. for (int i = 0; i < objects.Count - 1; i++)
  113. {
  114. duplicateName = false;
  115. for (int j = i + 1; j < objects.Count; j++)
  116. {
  117. if (token.IsCancellationRequested)
  118. return null;
  119. if (objects[j] is ReportComponentBase && objects[i].Name == objects[j].Name)
  120. {
  121. listError.Add(new ValidationError(objects[j].Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,DuplicateName"), (ReportComponentBase)objects[j]));
  122. duplicateName = true;
  123. }
  124. }
  125. if (objects[i] is ReportComponentBase && duplicateName)
  126. listError.Add(new ValidationError(objects[i].Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,DuplicateName"), (ReportComponentBase)objects[i]));
  127. }
  128. }
  129. catch
  130. {
  131. // validator should not crash the app
  132. return null;
  133. }
  134. return listError.Distinct().ToList();
  135. }
  136. }
  137. }