AvalonSyntaxEditor.Completion.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using FastReport.Controls;
  2. using FastReport.Editor.Syntax.Parsers;
  3. using FastReport.Engine;
  4. using FastReport.Utils;
  5. using ICSharpCode.AvalonEdit.CodeCompletion;
  6. using ICSharpCode.AvalonEdit.Document;
  7. using ICSharpCode.AvalonEdit.Editing;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Reflection;
  12. using System.Windows.Forms;
  13. namespace FastReport.Design.PageDesigners.Code
  14. {
  15. partial class AvalonSyntaxEditor
  16. {
  17. private void DoCodeCompletion(CompletionEventArgs e)
  18. {
  19. List<string> parts = e.Text.Split('.').ToList();
  20. string filter = "";
  21. if (e.Action == CompletionAction.CtrlSpacePressed)
  22. {
  23. // last item is incomplete - we will use it as a filter
  24. if (parts.Count > 0)
  25. {
  26. filter = parts[parts.Count - 1];
  27. parts.RemoveAt(parts.Count - 1);
  28. }
  29. }
  30. if (parts.Count == 0)
  31. {
  32. // list all report objects
  33. var list = new List<NamedItem>();
  34. foreach (Base obj in report.AllObjects)
  35. {
  36. if (string.IsNullOrEmpty(obj.Name))
  37. continue;
  38. list.Add(new NamedItem(obj.Name, obj.GetType()));
  39. }
  40. list.Add(new NamedItem("Report", typeof(Report)));
  41. list.Add(new NamedItem("Engine", typeof(ReportEngine)));
  42. list.Sort((x, y) => x.Name.CompareTo(y.Name));
  43. foreach (var obj in list)
  44. {
  45. if (obj.Name.IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) == -1)
  46. continue;
  47. string description = obj.Type.Name + " " + obj.Name;
  48. System.Drawing.Image image = null;
  49. var objInfo = RegisteredObjects.FindObject(obj.Type);
  50. if (objInfo != null)
  51. image = report.Designer.GetImage(objInfo.ImageIndex);
  52. e.CompletionData.Add(new CompletionData(obj.Name, description, image));
  53. }
  54. }
  55. else
  56. {
  57. Type rootType = null;
  58. // report object
  59. object root = report.FindObject(parts[0]);
  60. if (root != null)
  61. rootType = root.GetType();
  62. else
  63. {
  64. // some frequently used types like Color?
  65. if (parts[0] == "Color")
  66. rootType = typeof(System.Drawing.Color);
  67. else if (parts[0] == "Report")
  68. rootType = typeof(Report);
  69. else if (parts[0] == "Engine")
  70. rootType = typeof(ReportEngine);
  71. }
  72. if (rootType != null)
  73. {
  74. for (int i = 1; i < parts.Count; i++)
  75. {
  76. PropertyInfo member = null;
  77. try
  78. {
  79. member = rootType.GetProperty(parts[i]);
  80. }
  81. catch
  82. {
  83. // ambiguous properties found, take first one
  84. member = rootType.GetProperties().Where(x => x.Name == parts[i]).FirstOrDefault();
  85. }
  86. if (member != null)
  87. rootType = member.PropertyType;
  88. else
  89. {
  90. rootType = null;
  91. break;
  92. }
  93. }
  94. }
  95. if (rootType != null)
  96. {
  97. if (e.Action == CompletionAction.EqualEntered)
  98. {
  99. if (rootType.IsEnum)
  100. {
  101. // list enum members
  102. foreach(var name in Enum.GetNames(rootType))
  103. {
  104. var fieldInfo = rootType.GetField(name);
  105. e.CompletionData.Add(new CompletionData(rootType.Name + "." + name, ReflectionRepository.DescriptionHelper.GetDescription(fieldInfo), null));
  106. }
  107. }
  108. }
  109. else
  110. {
  111. var members = rootType.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).ToList();
  112. members.Sort((x, y) => (x.Name.CompareTo(y.Name)));
  113. foreach (var member in members)
  114. {
  115. if (!string.IsNullOrEmpty(filter) && member.Name.IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) == -1)
  116. continue;
  117. string description = "";
  118. System.Drawing.Image image = null;
  119. if (member.MemberType == MemberTypes.Property)
  120. {
  121. var propInfo = member as PropertyInfo;
  122. image = report.Designer.GetImage(78);
  123. description = report.CodeHelper.GetPropertySignature(propInfo, true);
  124. description += "<br/>" + ReflectionRepository.DescriptionHelper.GetDescription(member);
  125. }
  126. else if (member.MemberType == MemberTypes.Method)
  127. {
  128. var methodInfo = member as MethodInfo;
  129. if (methodInfo.IsSpecialName)
  130. continue;
  131. image = report.Designer.GetImage(199);
  132. description = report.CodeHelper.GetMethodSignature(methodInfo, true);
  133. description += "<br/>" + ReflectionRepository.DescriptionHelper.GetDescription(methodInfo);
  134. description += "<br/>";
  135. foreach (ParameterInfo parInfo in methodInfo.GetParameters())
  136. {
  137. // special case - skip "thisReport" parameter
  138. if (parInfo.Name == "thisReport")
  139. continue;
  140. string s = ReflectionRepository.DescriptionHelper.GetDescription(parInfo);
  141. s = s.Replace("<b>", "{i}").Replace("</b>:", "{/i}").Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("{i}", "<i>").Replace("{/i}", "</i>");
  142. description += "<br/>" + s + "<br/>";
  143. }
  144. description = description.Replace("\t", "<br/>");
  145. }
  146. else
  147. {
  148. continue;
  149. }
  150. if (description.EndsWith("<br/>"))
  151. description = description.Substring(0, description.Length - 5);
  152. e.CompletionData.Add(new CompletionData(member.Name, description, image));
  153. }
  154. }
  155. }
  156. }
  157. }
  158. private class NamedItem
  159. {
  160. public string Name { get; }
  161. public Type Type { get; }
  162. public NamedItem(string name, Type type)
  163. {
  164. Name = name;
  165. Type = type;
  166. }
  167. }
  168. private class CompletionData : ICompletionData
  169. {
  170. private string htmlDescription;
  171. private HtmlDescriptionTextBlock descriptionTextBlock;
  172. public CompletionData(string text, string htmlDescription, System.Drawing.Image image)
  173. {
  174. this.Text = text;
  175. this.htmlDescription = htmlDescription;
  176. this.Image = Helper.GetImage(image);
  177. }
  178. public System.Windows.Media.ImageSource Image { get; }
  179. public string Text { get; private set; }
  180. public object Content => this.Text;
  181. public object Description
  182. {
  183. get
  184. {
  185. if (descriptionTextBlock == null)
  186. CreateTextBlock();
  187. return descriptionTextBlock;
  188. }
  189. set { }
  190. }
  191. public double Priority => 0;
  192. public void Complete(TextArea textArea, ISegment completionSegment, EventArgs insertionRequestEventArgs)
  193. {
  194. textArea.Document.Replace(completionSegment, this.Text);
  195. }
  196. private void CreateTextBlock()
  197. {
  198. descriptionTextBlock = new HtmlDescriptionTextBlock();
  199. descriptionTextBlock.Image = this.Image;
  200. descriptionTextBlock.Description = this.htmlDescription;
  201. descriptionTextBlock.ParseDescription();
  202. }
  203. }
  204. }
  205. }