WMDiagnostics.Mod 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. MODULE WMDiagnostics; (** AUTHOR "staubesv"; PURPOSE "Visual Component for Diagnostics Interface"; *)
  2. IMPORT
  3. Locks, Strings, Diagnostics, Files, Streams,
  4. WMRectangles, WMGraphics, WMGraphicUtilities, WMBitmapFont,
  5. WMEvents, WMProperties, WMGrids, WMTextView;
  6. CONST
  7. TypeInformation* = Diagnostics.TypeInformation;
  8. TypeWarning* = Diagnostics.TypeWarning;
  9. TypeError* = Diagnostics.TypeError;
  10. (* Error grid colors *)
  11. ColorError = LONGINT(0FF3030A0H);
  12. ColorWarning = LONGINT(0D0D040C0H);
  13. ColorPCPosition = 0007F00A0H;
  14. (* Textview position marker pictures *)
  15. PictureError = "PETIcons.tar://errorpos.png";
  16. PictureWarning = "PETIcons.tar://warningpos.png";
  17. PicturePCPosition = "PETIcons.tar://pcpos.png";
  18. InitialArraySize = 16;
  19. Less = -1;
  20. Equal = 0;
  21. Greater = 1;
  22. SortByTypeAscending* = 0;
  23. SortByTypeDescending* = 1;
  24. SortByPositionAscending* = 2;
  25. SortByPositionDescending* = 3;
  26. TYPE
  27. Entry* = RECORD
  28. type- : LONGINT;
  29. source- : Files.FileName;
  30. position-: Streams.Position;
  31. message- : ARRAY 256 OF CHAR;
  32. END;
  33. EntryArray = POINTER TO ARRAY OF Entry;
  34. TYPE
  35. Model* = OBJECT(Diagnostics.Diagnostics)
  36. VAR
  37. entries : EntryArray;
  38. nofEntries- : LONGINT;
  39. nofInformations: LONGINT;
  40. nofWarnings : LONGINT;
  41. nofErrors : LONGINT;
  42. lock : Locks.RWLock;
  43. onChanged- : WMEvents.EventSource;
  44. changed : BOOLEAN;
  45. notificationEnabled : BOOLEAN;
  46. PROCEDURE &Init*; (** proctected *)
  47. BEGIN
  48. entries := NIL;
  49. nofEntries := 0;
  50. nofErrors := 0; nofWarnings := 0; nofInformations := 0;
  51. NEW(lock);
  52. NEW(onChanged, NIL, NIL, NIL, NIL);
  53. changed := FALSE;
  54. notificationEnabled := TRUE;
  55. END Init;
  56. (** Inform views about updates *)
  57. PROCEDURE EnableNotification*;
  58. BEGIN
  59. AcquireWrite;
  60. notificationEnabled := TRUE;
  61. ReleaseWrite;
  62. END EnableNotification;
  63. (** Don't inform views about updates *)
  64. PROCEDURE DisableNotification*;
  65. BEGIN
  66. AcquireWrite;
  67. notificationEnabled := FALSE;
  68. ReleaseWrite;
  69. END DisableNotification;
  70. (** Acquire read lock. *)
  71. PROCEDURE AcquireRead*;
  72. BEGIN
  73. lock.AcquireRead;
  74. END AcquireRead;
  75. (** Release read lock *)
  76. PROCEDURE ReleaseRead*;
  77. BEGIN
  78. lock.ReleaseRead;
  79. END ReleaseRead;
  80. (** Acquire write lock *)
  81. PROCEDURE AcquireWrite*;
  82. BEGIN
  83. lock.AcquireWrite;
  84. END AcquireWrite;
  85. (** Release write lock. If the data has changed, all listeners will be notified when the last
  86. writer releases its lock *)
  87. PROCEDURE ReleaseWrite*;
  88. VAR notifyListeners : BOOLEAN;
  89. BEGIN
  90. (* If the last writer releases the lock and the model data has changed, we have to notify interested listeners *)
  91. notifyListeners := notificationEnabled & (lock.GetWLockLevel() = 1) & changed;
  92. IF notificationEnabled THEN changed := FALSE; END;
  93. lock.ReleaseWrite;
  94. IF notifyListeners THEN
  95. onChanged.Call(SELF);
  96. END;
  97. END ReleaseWrite;
  98. (** Dispose all entries *)
  99. PROCEDURE Clear*;
  100. BEGIN
  101. AcquireWrite;
  102. changed := changed OR (entries # NIL) OR (nofEntries # 0) OR (nofErrors # 0) OR (nofWarnings # 0) OR (nofInformations # 0);
  103. entries := NIL;
  104. nofEntries := 0;
  105. nofErrors := 0; nofWarnings := 0; nofInformations := 0;
  106. ReleaseWrite;
  107. END Clear;
  108. (* Make sure that <entries> cannot hold at least one more entry *)
  109. PROCEDURE CheckEntriesSize;
  110. VAR newEntries : EntryArray; i : LONGINT;
  111. BEGIN
  112. ASSERT(lock.HasWriteLock());
  113. IF (entries = NIL) THEN
  114. NEW(entries, InitialArraySize);
  115. ELSIF (nofEntries >= LEN(entries)) THEN
  116. NEW(newEntries, 2 * LEN(entries));
  117. FOR i := 0 TO nofEntries - 1 DO
  118. newEntries[i] := entries[i];
  119. END;
  120. entries := newEntries;
  121. END;
  122. END CheckEntriesSize;
  123. PROCEDURE Error*(CONST source : ARRAY OF CHAR; position : Streams.Position; CONST message : ARRAY OF CHAR);
  124. BEGIN
  125. Add(TypeError, source, position, message, nofErrors)
  126. END Error;
  127. PROCEDURE Warning*(CONST source : ARRAY OF CHAR; position : Streams.Position; CONST message : ARRAY OF CHAR);
  128. BEGIN
  129. Add(TypeWarning, source, position, message, nofWarnings);
  130. END Warning;
  131. PROCEDURE Information*(CONST source : ARRAY OF CHAR; position : Streams.Position; CONST message : ARRAY OF CHAR);
  132. BEGIN
  133. Add(TypeInformation, source, position, message, nofInformations);
  134. END Information;
  135. PROCEDURE Exists(type: WORD; position : Streams.Position; CONST message: ARRAY OF CHAR) : BOOLEAN;
  136. VAR i : LONGINT;
  137. BEGIN
  138. i := 0;
  139. WHILE (i < nofEntries) & ((entries[i].type # type) OR (entries[i].position # position) OR (entries[i].message # message)) DO
  140. INC(i);
  141. END;
  142. RETURN (nofEntries > 0) & (i < nofEntries);
  143. END Exists;
  144. PROCEDURE Add(type: WORD; CONST source : ARRAY OF CHAR; position : Streams.Position; CONST message : ARRAY OF CHAR; VAR counter: LONGINT);
  145. BEGIN
  146. AcquireWrite;
  147. IF ~Exists(type, position, message) THEN
  148. CheckEntriesSize;
  149. entries[nofEntries].type := type;
  150. COPY(source, entries[nofEntries].source);
  151. entries[nofEntries].position := position;
  152. COPY(message, entries[nofEntries].message);
  153. INC(nofEntries); INC(counter);
  154. changed := TRUE;
  155. END;
  156. ReleaseWrite;
  157. END Add;
  158. (* Returns a string summarizing the number of errors and warnings *)
  159. PROCEDURE GetSummary(VAR summary : ARRAY OF CHAR);
  160. VAR nbr : ARRAY 8 OF CHAR;
  161. BEGIN
  162. AcquireRead;
  163. summary := "";
  164. IF (nofErrors > 0) THEN
  165. Strings.IntToStr(nofErrors, nbr); Strings.Append(summary, nbr);
  166. Strings.Append(summary, " error");
  167. IF (nofErrors > 1) THEN
  168. Strings.Append(summary, "s");
  169. END;
  170. ELSE
  171. summary := "no errors";
  172. END;
  173. IF (nofWarnings > 0) THEN
  174. Strings.Append(summary, ", "); Strings.IntToStr(nofWarnings, nbr);
  175. Strings.Append(summary, nbr);
  176. Strings.Append(summary, " warning");
  177. IF (nofWarnings > 1) THEN
  178. Strings.Append(summary, "s");
  179. END;
  180. END;
  181. ReleaseRead;
  182. END GetSummary;
  183. PROCEDURE Synchronize(VAR entries : ViewEntryArray; VAR nofEntries : LONGINT);
  184. VAR dest : LONGINT;
  185. PROCEDURE Insert(type: LONGINT);
  186. VAR i: LONGINT;
  187. BEGIN
  188. FOR i := 0 TO nofEntries - 1 DO
  189. IF SELF.entries[i].type = type THEN
  190. entries[dest].type := SELF.entries[i].type;
  191. entries[dest].position := SELF.entries[i].position;
  192. entries[dest].source := SELF.entries[i].source;
  193. entries[dest].message := SELF.entries[i].message;
  194. INC(dest);
  195. END;
  196. END;
  197. END Insert;
  198. BEGIN
  199. AcquireRead;
  200. IF (SELF.entries = NIL) THEN
  201. nofEntries := 0;
  202. ELSE
  203. IF (entries = NIL) OR (LEN(SELF.entries) > LEN(entries)) THEN NEW(entries, LEN(SELF.entries)); END;
  204. nofEntries := SELF.nofEntries;
  205. Insert(Diagnostics.TypeError);
  206. Insert(Diagnostics.TypeWarning);
  207. Insert(Diagnostics.TypeInformation);
  208. END;
  209. ReleaseRead;
  210. END Synchronize;
  211. END Model;
  212. TYPE
  213. CompareProcedure = PROCEDURE(CONST entry1, entry2 : Entry) : LONGINT;
  214. ViewEntry* = RECORD (Entry)
  215. pos- : POINTER TO ARRAY OF WMTextView.PositionMarker;
  216. END;
  217. ViewEntryArray = POINTER TO ARRAY OF ViewEntry;
  218. CellInfo* = OBJECT(WMGrids.CellPositionInfo)
  219. VAR
  220. entryValid- : BOOLEAN;
  221. entry- : ViewEntry;
  222. PROCEDURE &Init(entryValid : BOOLEAN; CONST entry : ViewEntry; column, row : LONGINT);
  223. BEGIN
  224. SELF.entryValid := entryValid;
  225. SELF.entry := entry;
  226. pos.col := column;
  227. pos.row := row;
  228. END Init;
  229. END CellInfo;
  230. TYPE
  231. DiagnosticsView* = OBJECT(WMGrids.GenericGrid)
  232. VAR
  233. showMarkers- : WMProperties.BooleanProperty;
  234. showMarkersI : BOOLEAN;
  235. sortBy- : WMProperties.Int32Property;
  236. sortByI : LONGINT;
  237. entries : ViewEntryArray;
  238. nofEntries : LONGINT;
  239. model : Model;
  240. textViews : POINTER TO ARRAY OF WMTextView.TextView;
  241. summary : ARRAY 256 OF CHAR;
  242. PROCEDURE &Init*;
  243. BEGIN
  244. Init^;
  245. SetNameAsString(StrDiagnosticsView);
  246. SetDrawCellProc(DrawCell);
  247. NEW(showMarkers, PrototypeShowMarkers, NIL, NIL); properties.Add(showMarkers);
  248. showMarkersI := showMarkers.Get();
  249. NEW(sortBy, PrototypeSortBy, NIL, NIL); properties.Add(sortBy);
  250. sortByI := sortBy.Get();
  251. entries := NIL;
  252. nofEntries := 0;
  253. model := NIL;
  254. textViews := NIL;
  255. summary := "";
  256. nofCols.Set(3);
  257. nofRows.Set(1);
  258. onClick.Add(OnClickHandler);
  259. END Init;
  260. PROCEDURE PropertyChanged*(sender, property : ANY);
  261. BEGIN
  262. IF (property = showMarkers) THEN
  263. ShowMarkers(showMarkers.Get());
  264. ELSIF (property = sortBy) THEN
  265. SortBy(sortBy.Get());
  266. ELSE
  267. PropertyChanged^(sender, property);
  268. END
  269. END PropertyChanged;
  270. PROCEDURE RecacheProperties*;
  271. BEGIN
  272. RecacheProperties^;
  273. ShowMarkers(showMarkers.Get());
  274. SortBy(sortBy.Get());
  275. END RecacheProperties;
  276. PROCEDURE OnClickHandler(sender, data : ANY);
  277. CONST Position = 0;
  278. VAR column, row, newMode : LONGINT;
  279. BEGIN
  280. IF ~IsCallFromSequencer() THEN sequencer.ScheduleEvent(SELF.OnClickHandler, sender, data)
  281. ELSE
  282. IF (data # NIL) & (data IS CellInfo) & ~(data(CellInfo).entryValid) THEN
  283. column := data(CellInfo).pos.col;
  284. row := data(CellInfo).pos.row;
  285. IF (row = 0) THEN
  286. CASE sortByI OF
  287. |SortByTypeAscending:
  288. IF (column = Position) THEN
  289. newMode := SortByTypeDescending;
  290. END;
  291. |SortByTypeDescending:
  292. IF (column = Position) THEN
  293. newMode := SortByTypeAscending;
  294. END;
  295. |SortByPositionAscending:
  296. IF (column = Position) THEN
  297. newMode := SortByPositionDescending;
  298. END;
  299. |SortByPositionDescending:
  300. IF (column = Position) THEN
  301. newMode := SortByPositionAscending;
  302. END;
  303. ELSE
  304. newMode := sortByI; (* don't change *)
  305. END;
  306. sortBy.Set(newMode);
  307. END;
  308. END;
  309. END;
  310. END OnClickHandler;
  311. PROCEDURE ShowMarkers(enable : BOOLEAN);
  312. VAR i, j : LONGINT;
  313. BEGIN
  314. Acquire;
  315. IF (enable # showMarkersI) THEN
  316. showMarkersI := enable;
  317. IF (textViews # NIL) THEN
  318. FOR i := 0 TO nofEntries - 1 DO
  319. FOR j := 0 TO LEN(textViews) - 1 DO
  320. IF (entries[i].pos[j] # NIL) THEN
  321. entries[i].pos[j].SetVisible(showMarkersI);
  322. END;
  323. END;
  324. END;
  325. END;
  326. Invalidate;
  327. END;
  328. Release;
  329. END ShowMarkers;
  330. PROCEDURE SortBy(mode : LONGINT);
  331. BEGIN
  332. ASSERT(
  333. (mode = SortByTypeAscending) OR (mode = SortByTypeDescending) OR
  334. (mode = SortByPositionAscending) OR (mode = SortByPositionDescending)
  335. );
  336. Acquire;
  337. IF (mode # sortByI) THEN
  338. sortByI := mode;
  339. CASE sortByI OF
  340. |SortByTypeAscending: SortEntries(CompareByType, TRUE);
  341. |SortByTypeDescending: SortEntries(CompareByType, FALSE);
  342. |SortByPositionAscending: SortEntries(CompareByPosition, TRUE);
  343. |SortByPositionDescending: SortEntries(CompareByPosition, FALSE);
  344. END;
  345. Invalidate;
  346. END;
  347. Release;
  348. END SortBy;
  349. PROCEDURE GetCellData*(column, row : LONGINT) : ANY; (* override *)
  350. VAR info : CellInfo; entryValid : BOOLEAN; entry : ViewEntry;
  351. BEGIN
  352. Acquire;
  353. IF (0 <= row - 1) & (row - 1 < nofEntries) THEN
  354. entryValid := TRUE;
  355. entry := entries[row - 1];
  356. ELSE
  357. entryValid := FALSE;
  358. END;
  359. NEW(info, entryValid, entry, column, row);
  360. Release;
  361. RETURN info;
  362. END GetCellData;
  363. PROCEDURE AddPositionMarkers;
  364. VAR picture : Files.FileName; i, j : LONGINT;
  365. BEGIN (* caller holds lock *)
  366. IF (textViews # NIL) THEN
  367. FOR i := 0 TO nofEntries - 1 DO
  368. IF (entries[i].type = Diagnostics.TypeError) THEN
  369. picture := PictureError;
  370. ELSIF (entries[i].type = Diagnostics.TypeWarning) THEN
  371. picture := PictureWarning;
  372. ELSE
  373. picture := "";
  374. END;
  375. IF (entries[i].position # Streams.Invalid) & (textViews # NIL) THEN
  376. NEW(entries[i].pos, LEN(textViews));
  377. FOR j := 0 TO LEN(textViews) - 1 DO
  378. entries[i].pos[j] := textViews[j].CreatePositionMarker();
  379. IF (picture # "") THEN entries[i].pos[j].Load(picture); END;
  380. entries[i].pos[j].SetPosition(entries[i].position);
  381. END;
  382. END;
  383. END;
  384. END;
  385. END AddPositionMarkers;
  386. PROCEDURE RemovePositionMarkers;
  387. VAR i, j : LONGINT;
  388. BEGIN (* caller holds lock *)
  389. IF (textViews # NIL) THEN
  390. FOR i := 0 TO nofEntries-1 DO
  391. FOR j := 0 TO LEN(textViews)-1 DO
  392. IF (entries[i].pos # NIL) & (entries[i].pos[j] # NIL) THEN
  393. textViews[j].RemovePositionMarker(entries[i].pos[j]);
  394. entries[i].pos[j] := NIL;
  395. END;
  396. END;
  397. END;
  398. END;
  399. END RemovePositionMarkers;
  400. PROCEDURE GetFirstPosition*(VAR positions : ARRAY OF LONGINT; VAR type: LONGINT);
  401. VAR i : LONGINT;
  402. BEGIN
  403. Acquire;
  404. ASSERT((textViews # NIL) & (LEN(textViews) = LEN(positions)));
  405. IF (nofEntries > 0) THEN
  406. FOR i := 0 TO LEN(textViews)-1 DO
  407. IF (entries[0].pos # NIL) & (entries[0].pos[i] # NIL) THEN
  408. positions[i] := entries[0].pos[i].GetPosition();
  409. ELSE
  410. positions[i] := Streams.Invalid;
  411. END;
  412. type := entries[0].type;
  413. END;
  414. ELSE
  415. FOR i := 0 TO LEN(positions)-1 DO positions[i] := Streams.Invalid; END;
  416. END;
  417. Release;
  418. END GetFirstPosition;
  419. PROCEDURE GetNearestPosition*(cursorPosition, editorIndex : LONGINT; forward : BOOLEAN; VAR nearestPosition : LONGINT; VAR number : LONGINT);
  420. VAR pos, i : LONGINT;
  421. BEGIN
  422. Acquire;
  423. ASSERT((textViews # NIL) & (0 <= editorIndex) & (editorIndex < LEN(textViews)));
  424. nearestPosition := -1; number := 1; (* row 0 is grid title *)
  425. i := 0;
  426. LOOP
  427. IF (i >= nofEntries) OR (entries[i].pos = NIL) OR (entries[i].pos[editorIndex] = NIL) THEN EXIT; END;
  428. pos := entries[i].pos[editorIndex].GetPosition();
  429. IF forward & (pos > cursorPosition) THEN
  430. IF (nearestPosition = -1) OR (pos < nearestPosition) THEN nearestPosition := pos; number := i+1; END;
  431. ELSIF ~forward & (pos < cursorPosition) THEN
  432. IF (nearestPosition = -1) OR (pos > nearestPosition) THEN nearestPosition := pos; number := i+1; END;
  433. END;
  434. INC(i);
  435. END;
  436. IF (nearestPosition = -1) THEN
  437. nearestPosition := cursorPosition;
  438. IF forward & (i > 1) THEN (* select maximum row *) number := i; END;
  439. END;
  440. Release;
  441. END GetNearestPosition;
  442. PROCEDURE SelectEntry*(number : LONGINT; moveTo : BOOLEAN);
  443. BEGIN
  444. Acquire;
  445. IF (0 <= number) & (number <= nofEntries) THEN
  446. SetSelection(0, number, 2, number);
  447. IF moveTo THEN
  448. SetTopPosition(0, number, TRUE);
  449. END;
  450. END;
  451. Release;
  452. END SelectEntry;
  453. PROCEDURE SortEntries(compare : CompareProcedure; ascending : BOOLEAN);
  454. VAR result, i, j : LONGINT; temp : ViewEntry;
  455. BEGIN
  456. (* caller must hold lock *)
  457. ASSERT(compare # NIL);
  458. IF (nofEntries > 1) THEN
  459. (* bubble sort *)
  460. FOR i := 0 TO nofEntries - 1 DO
  461. FOR j := 1 TO nofEntries - 1 DO
  462. result := compare(entries[j-1], entries[j]);
  463. IF (ascending & (result = Greater)) OR (~ascending & (result = Less)) THEN
  464. temp := entries[j - 1];
  465. entries[j - 1] := entries[j];
  466. entries[j] := temp;
  467. END;
  468. END;
  469. END;
  470. END;
  471. END SortEntries;
  472. PROCEDURE SetTextViews*(CONST textViews : ARRAY OF WMTextView.TextView);
  473. VAR i : LONGINT;
  474. BEGIN
  475. Acquire;
  476. RemovePositionMarkers;
  477. NEW(SELF.textViews, LEN(textViews));
  478. FOR i := 0 TO LEN(textViews)-1 DO
  479. ASSERT(textViews[i] # NIL);
  480. SELF.textViews[i]:= textViews[i];
  481. END;
  482. AddPositionMarkers;
  483. Release;
  484. END SetTextViews;
  485. PROCEDURE SetModel*(model : Model);
  486. BEGIN
  487. Acquire;
  488. IF (SELF.model # NIL) THEN SELF.model.onChanged.Remove(ModelChanged); END;
  489. SELF.model := model;
  490. IF (SELF.model # NIL) THEN SELF.model.onChanged.Add(ModelChanged); END;
  491. Release;
  492. Invalidate;
  493. END SetModel;
  494. PROCEDURE ModelChanged(sender, data : ANY);
  495. BEGIN
  496. IF ~IsCallFromSequencer() THEN sequencer.ScheduleEvent(SELF.ModelChanged, sender, data);
  497. ELSE
  498. RemovePositionMarkers;
  499. model.AcquireRead;
  500. model.Synchronize(entries, nofEntries);
  501. model.GetSummary(summary);
  502. model.ReleaseRead;
  503. nofRows.Set(nofEntries + 1); (* 1 for title row *)
  504. AddPositionMarkers;
  505. SetTopPosition(0, 0, TRUE);
  506. Invalidate;
  507. END;
  508. END ModelChanged;
  509. PROCEDURE DrawCell(canvas : WMGraphics.Canvas; w, h : LONGINT; state : SET; x, y : LONGINT);
  510. VAR color: LONGINT; str : ARRAY 128 OF CHAR;
  511. BEGIN
  512. color := WMGraphics.RGBAToColor(255, 255, 255, 255);
  513. IF state * {WMGrids.CellFixed, WMGrids.CellSelected} = {WMGrids.CellFixed, WMGrids.CellSelected} THEN
  514. color := WMGraphics.RGBAToColor(0, 128, 255, 255)
  515. ELSIF WMGrids.CellFixed IN state THEN
  516. color := WMGraphics.RGBAToColor(196, 196, 196, 255)
  517. ELSIF WMGrids.CellSelected IN state THEN
  518. color := WMGraphics.RGBAToColor(196, 196, 255, 255)
  519. END;
  520. canvas.SetColor(WMGraphics.RGBAToColor(0, 0, 0, 255));
  521. canvas.SetFont(WMBitmapFont.bimbofont);
  522. canvas.Fill(WMRectangles.MakeRect(0, 0, w, h), color, WMGraphics.ModeCopy);
  523. IF (WMGrids.CellFocused IN state) & ~(WMGrids.CellHighlighted IN state) THEN
  524. WMGraphicUtilities.DrawBevel(canvas, WMRectangles.MakeRect(0, 0, w, h), 1, TRUE, WMGraphics.RGBAToColor(0, 0, 0, 196),
  525. WMGraphics.ModeSrcOverDst)
  526. END;
  527. IF y = 0 THEN
  528. CASE x OF
  529. | 0 : str := "pos"
  530. | 1 : str := "err"
  531. | 2 :
  532. str := "Error Str";
  533. Strings.Append(str, " ("); Strings.Append(str, summary); Strings.Append(str, ")");
  534. ELSE
  535. END;
  536. canvas.DrawString(4, h - 4, str);
  537. ELSIF (0 <= y - 1) & (y - 1 < nofEntries) THEN
  538. CASE x OF
  539. | 0 :
  540. IF (entries[y - 1].pos # NIL) & (entries[y - 1].pos[0] # NIL) THEN Strings.IntToStr(entries[y - 1].pos[0].GetPosition(), str) END;
  541. IF entries[y - 1].type = TypeError THEN
  542. canvas.Fill(WMRectangles.MakeRect(0, 0, w, h), ColorError, WMGraphics.ModeSrcOverDst);
  543. ELSIF entries[y - 1].type = TypeWarning THEN
  544. canvas.Fill(WMRectangles.MakeRect(0, 0, w, h), ColorWarning, WMGraphics.ModeSrcOverDst);
  545. ELSIF entries[y - 1].type = TypeInformation THEN
  546. canvas.Fill(WMRectangles.MakeRect(0, 0, w, h), ColorPCPosition, WMGraphics.ModeSrcOverDst);
  547. ELSIF entries[y - 1].type = TypeInformation THEN
  548. (* do nothing *)
  549. END;
  550. | 2 : COPY(entries[y - 1].message, str)
  551. ELSE
  552. END;
  553. canvas.DrawString(4, h - 4, str);
  554. END;
  555. END DrawCell;
  556. END DiagnosticsView;
  557. VAR
  558. StrDiagnosticsView : Strings.String;
  559. PrototypeShowMarkers : WMProperties.BooleanProperty;
  560. PrototypeSortBy : WMProperties.Int32Property;
  561. PROCEDURE CompareByPosition(CONST e1, e2 : Entry) : LONGINT;
  562. VAR result : LONGINT;
  563. BEGIN
  564. IF (e1.position < e2.position) THEN result := Less;
  565. ELSIF (e1.position > e2.position) THEN result := Greater;
  566. ELSE
  567. result := Equal;
  568. END;
  569. RETURN result;
  570. END CompareByPosition;
  571. PROCEDURE CompareByType(CONST e1, e2 : Entry) : LONGINT;
  572. VAR result : LONGINT;
  573. BEGIN
  574. IF (e1.type < e2.type) THEN result := Less;
  575. ELSIF (e1.type > e2.type) THEN result := Greater;
  576. ELSE
  577. result := CompareByPosition(e1, e2);
  578. END;
  579. RETURN result;
  580. END CompareByType;
  581. PROCEDURE InitStrings;
  582. BEGIN
  583. StrDiagnosticsView := Strings.NewString("DiagnosticsView");
  584. END InitStrings;
  585. PROCEDURE InitPrototypes;
  586. BEGIN
  587. NEW(PrototypeShowMarkers, NIL, Strings.NewString("ShowMarkers"), Strings.NewString("Highlight errors in TextView?"));
  588. PrototypeShowMarkers.Set(TRUE);
  589. NEW(PrototypeSortBy, NIL, Strings.NewString("SortBy"), Strings.NewString("Sort grid by 0=type | 1=position | 2=errorCode"));
  590. PrototypeSortBy.Set(SortByTypeDescending);
  591. END InitPrototypes;
  592. BEGIN
  593. InitStrings;
  594. InitPrototypes;
  595. END WMDiagnostics.