WMXMLTree.Mod 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. MODULE WMXMLTree; (** AUTHOR "TF"; PURPOSE "Simple XML Viewer"; *)
  2. IMPORT
  3. Streams, XML, XMLObjects, WMGraphics,
  4. WMComponents, WMStandardComponents, WMTextView, WMEditors, WMEvents, Strings, TextUtilities, Texts,
  5. WMTrees, XMLScanner, XMLParser, UTF8Strings;
  6. TYPE
  7. Error* = RECORD
  8. pos- : LONGINT;
  9. line-, row- : LONGINT;
  10. msg- : ARRAY 128 OF CHAR;
  11. END;
  12. ErrorList* = POINTER TO ARRAY OF Error;
  13. TYPE
  14. XMLView* = OBJECT(WMComponents.VisualComponent)
  15. VAR
  16. tree : WMTrees.Tree;
  17. treeView : WMTrees.TreeView;
  18. toolbar : WMStandardComponents.Panel;
  19. errorMsg : WMEditors.Editor;
  20. refresh- : WMStandardComponents.Button;
  21. onRefresh- : WMEvents.EventSource;
  22. label- : WMStandardComponents.Label;
  23. hasErrors :BOOLEAN;
  24. highlight : WMTextView.Highlight;
  25. (** Show error messages in XMLView? Default: FALSE *)
  26. showErrorMessage* : BOOLEAN;
  27. errorList : ErrorList;
  28. text : Texts.Text;
  29. editor : WMEditors.Editor;
  30. PROCEDURE &Init*;
  31. BEGIN
  32. Init^;
  33. SetNameAsString(StrXMLView);
  34. NEW(onRefresh, SELF, NIL, NIL, NIL);
  35. NEW(toolbar); toolbar.bounds.SetHeight(20); toolbar.alignment.Set(WMComponents.AlignTop);
  36. AddContent(toolbar);
  37. NEW(label); label.alignment.Set(WMComponents.AlignTop);
  38. label.fillColor.Set(0CCCCCCFFH);
  39. label.caption.SetAOC("XML Structure (alpha)");
  40. label.bounds.SetHeight(20);
  41. SELF.AddContent(label);
  42. NEW(refresh); refresh.caption.SetAOC("Refresh"); refresh.alignment.Set(WMComponents.AlignLeft);
  43. toolbar.AddContent(refresh);
  44. refresh.onClick.Add(Refresh);
  45. NEW(errorMsg);
  46. errorMsg.bounds.SetHeight(150); errorMsg.alignment.Set(WMComponents.AlignTop);
  47. errorMsg.visible.Set(FALSE);
  48. AddContent(errorMsg);
  49. NEW(treeView); treeView.alignment.Set(WMComponents.AlignClient);
  50. treeView.onClickNode.Add(Click);
  51. AddContent(treeView);
  52. tree := treeView.GetTree();
  53. END Init;
  54. PROCEDURE SetEditor*(e: WMEditors.Editor);
  55. BEGIN
  56. IF e = editor THEN RETURN END;
  57. IF (highlight # NIL) & (editor # NIL) THEN
  58. editor.tv.RemoveHighlight(highlight);
  59. highlight := NIL
  60. END;
  61. text := e.text;
  62. editor := e;
  63. highlight := editor.tv.CreateHighlight();
  64. highlight.SetColor(LONGINT(0DDDD0060H));
  65. highlight.SetKind(WMTextView.HLOver)
  66. END SetEditor;
  67. PROCEDURE Click(sender, data : ANY);
  68. VAR p : ANY; a, b : LONGINT;
  69. BEGIN
  70. IF (data # NIL) & (data IS WMTrees.TreeNode) THEN
  71. tree.Acquire;
  72. p := tree.GetNodeData(data(WMTrees.TreeNode));
  73. tree.Release;
  74. IF (p # NIL) & (p IS XML.Element) THEN
  75. IF editor # NIL THEN
  76. text.AcquireRead;
  77. editor.tv.cursor.SetPosition(p(XML.Element).GetPos());
  78. editor.tv.cursor.SetVisible(TRUE);
  79. editor.tv.FindCommand(p(XML.Element).GetPos()-1, a, b);
  80. IF highlight # NIL THEN highlight.SetFromTo(a, b) END;
  81. text.ReleaseRead;
  82. END
  83. END
  84. END;
  85. END Click;
  86. PROCEDURE AddSubNode(node : WMTrees.TreeNode; xml : XML.Element );
  87. VAR en : XMLObjects.Enumerator;
  88. p : ANY; s,t,c : Strings.String;
  89. newNode : WMTrees.TreeNode;
  90. BEGIN
  91. NEW(newNode);
  92. tree.AddChildNode(node, newNode);
  93. tree.SetNodeData(newNode, xml);
  94. s := xml.GetName();
  95. t := xml.GetAttributeValue("name");
  96. IF (t#NIL) THEN
  97. NEW(c,Strings.Length(s^) + Strings.Length(t^) + 1 + 4);
  98. c[0] := 0X;
  99. IF (s # NIL) THEN
  100. Strings.Append(c^,s^);
  101. Strings.Append(c^,': ');
  102. END;
  103. Strings.Append(c^,'"');
  104. Strings.Append(c^,t^);
  105. Strings.Append(c^,'"');
  106. ELSE
  107. c := s;
  108. END;
  109. IF c # NIL THEN tree.SetNodeCaption(newNode, c) END;
  110. en := xml.GetContents();
  111. WHILE en.HasMoreElements() DO
  112. p := en.GetNext();
  113. IF p IS XML.Element THEN
  114. AddSubNode(newNode, p(XML.Element));
  115. END
  116. END;
  117. END AddSubNode;
  118. PROCEDURE SetDocument(xml : XML.Element);
  119. VAR en : XMLObjects.Enumerator;
  120. p : ANY;
  121. node : WMTrees.TreeNode;
  122. BEGIN
  123. NEW(node);
  124. tree.Acquire;
  125. tree.SetRoot(node);
  126. tree.SetNodeState(node, {WMTrees.NodeAlwaysExpanded});
  127. tree.SetNodeData(node, xml);
  128. IF xml # NIL THEN
  129. en := xml.GetContents();
  130. WHILE en.HasMoreElements() DO
  131. p := en.GetNext();
  132. IF p IS XML.Element THEN
  133. AddSubNode(node, p(XML.Element));
  134. END
  135. END
  136. END;
  137. tree.Release
  138. END SetDocument;
  139. (* Return a copy of the errorList or NIL in case of no errors *)
  140. PROCEDURE GetErrorList*() : ErrorList;
  141. VAR result : ErrorList; i : LONGINT;
  142. BEGIN
  143. IF errorList # NIL THEN
  144. NEW(result, LEN(errorList));
  145. FOR i := 0 TO LEN(errorList)-1 DO
  146. result[i] := errorList[i];
  147. END;
  148. END;
  149. RETURN result;
  150. END GetErrorList;
  151. PROCEDURE AddErrorToList(pos, line, row : LONGINT; CONST msg : ARRAY OF CHAR);
  152. VAR temp : ErrorList; i : LONGINT;
  153. BEGIN
  154. IF errorList = NIL THEN
  155. i := 0;
  156. NEW(errorList, 1);
  157. ELSE
  158. NEW(temp, LEN(errorList)+1);
  159. FOR i := 0 TO LEN(errorList)-1 DO
  160. temp[i] := errorList[i];
  161. END;
  162. errorList := temp;
  163. END;
  164. errorList[i].pos := pos;
  165. errorList[i].line := line;
  166. errorList[i].row := row;
  167. COPY(msg, errorList[i].msg);
  168. END AddErrorToList;
  169. PROCEDURE Error(pos, line, row: LONGINT; CONST msg: ARRAY OF CHAR);
  170. VAR tw : TextUtilities.TextWriter;
  171. BEGIN
  172. AddErrorToList(pos, line, row, msg);
  173. NEW(tw, errorMsg.text);
  174. tw.SetFontStyle({WMGraphics.FontBold});
  175. tw.String(msg); tw.Ln;
  176. tw.SetFontStyle({});
  177. tw.String("at pos "); tw.Int(pos, 0); tw.String(" (in line "); tw.Int(line, 0); tw.String(" row "); tw.Int(row, 0); tw.String(")"); tw.Ln;
  178. tw.Ln;
  179. hasErrors := TRUE;
  180. tw.Update
  181. END Error;
  182. PROCEDURE Refresh*(sender, data : ANY);
  183. VAR r : Streams.StringReader;
  184. scanner : XMLScanner.Scanner;
  185. parser : XMLParser.Parser;
  186. doc : XML.Document;
  187. tr : Texts.TextReader; ch : Texts.Char32; i, p : LONGINT; resstr : ARRAY 7 OF CHAR;
  188. out : Streams.Writer;
  189. ob : Strings.Buffer;
  190. s : Strings.String;
  191. BEGIN
  192. IF ~IsCallFromSequencer() THEN sequencer.ScheduleEvent(SELF.Refresh, sender, data)
  193. ELSE
  194. errorMsg.text.AcquireWrite;
  195. errorMsg.text.Delete(0, errorMsg.text.GetLength());
  196. errorMsg.text.ReleaseWrite;
  197. errorList := NIL;
  198. hasErrors := FALSE;
  199. IF text = NIL THEN RETURN END;
  200. text.AcquireRead;
  201. NEW(ob, (text.GetLength() * 3 DIV 2)); (* heuristic to avoid growing in most cases *)
  202. out := ob.GetWriter();
  203. NEW(tr, text);
  204. FOR i := 0 TO text.GetLength() - 1 DO
  205. tr.ReadCh(ch); p := 0;
  206. IF (ch > 0) & UTF8Strings.EncodeChar(ch, resstr, p) THEN out.String(resstr) END
  207. END;
  208. out.Update;
  209. text.ReleaseRead;
  210. NEW(r, ob.GetLength() + 1);
  211. s := ob.GetString();
  212. r.SetRaw(s^, 0, ob.GetLength());
  213. hasErrors := FALSE;
  214. NEW(scanner, r); scanner.reportError := Error;
  215. NEW(parser, scanner); parser.reportError := Error;
  216. doc := parser.Parse();
  217. errorMsg.visible.Set(showErrorMessage & hasErrors);
  218. IF hasErrors THEN errorMsg.tv.firstLine.Set(0);
  219. label.caption.SetAOC("XML Structure (ERRORS)");
  220. label.fillColor.Set(0FF0000FFH);
  221. ELSE
  222. label.caption.SetAOC("XML Structure");
  223. label.fillColor.Set(0CCCCCCFFH);
  224. END;
  225. IF doc # NIL THEN
  226. SetDocument(doc.GetRoot())
  227. END;
  228. onRefresh.Call(SELF);
  229. END
  230. END Refresh;
  231. END XMLView;
  232. VAR
  233. StrXMLView : Strings.String;
  234. BEGIN
  235. StrXMLView := Strings.NewString("XMLView");
  236. END WMXMLTree.