2
0

Stamps.txt 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. MODULE StdStamps;
  2. (* THIS IS TEXT COPY OF BlackBox 1.6-rc6 Std/Mod/Stamps.odc *)
  3. (* DO NOT EDIT *)
  4. (*
  5. StdStamps are used to keep track of document changes, in particular program texts.
  6. StdStamps carry a sequence number and a fingerprint of the document with them.
  7. Each time the document (and therefore its fingerprint) is changed and stored,
  8. the sequence number is incremented. (When determining the fingerprint of the
  9. document, whitespace is ignored, except in string literals.)
  10. Each StdStamp also keeps track of the history of most recent changes.
  11. For the last maxHistoryEntries sequence numbers, the date and time,
  12. and an optional one-line comment is stored. To avoid too many entries in the history
  13. while working on a module, the most recent history entry is overwritten upon the
  14. generation of a new sequence number if the current date is the same as the date in
  15. the history entry.
  16. *)
  17. IMPORT
  18. SYSTEM, (* SYSTEM.ROT only, for fingerprint calculation *)
  19. Strings, Dates, StdCmds,
  20. Ports, Models, Stores, Containers, Properties, Views, Controllers, Fonts,
  21. TextModels, TextSetters, TextMappers, TextViews, TextRulers;
  22. CONST
  23. setCommentKey = "#Std:Set Comment";
  24. maxHistoryEntries = 25;
  25. minVersion = 0; origStampVersion = 0; thisVersion = 2;
  26. TYPE
  27. History = ARRAY maxHistoryEntries OF RECORD
  28. fprint, snr: INTEGER; (* fingerprint, sequence number *)
  29. date: INTEGER; (* days since 1/1/1 *)
  30. time: INTEGER; (* min + 64 * hour *)
  31. comment: POINTER TO ARRAY OF CHAR; (* nil if no comment *)
  32. END;
  33. StdView = POINTER TO RECORD (Views.View)
  34. (*--snr: LONGINT;*)
  35. nentries: INTEGER; (* number of entries in history *)
  36. history: History; (* newest entry in history[0] *)
  37. cache: ARRAY 64 OF CHAR;
  38. END;
  39. SetCmtOp = POINTER TO RECORD (Stores.Operation)
  40. stamp: StdView;
  41. oldcomment: POINTER TO ARRAY OF CHAR;
  42. END;
  43. VAR
  44. comment*: RECORD
  45. s*: ARRAY 64 OF CHAR;
  46. END;
  47. PROCEDURE (op: SetCmtOp) Do;
  48. VAR temp: POINTER TO ARRAY OF CHAR;
  49. BEGIN
  50. temp := op.stamp.history[0].comment;
  51. op.stamp.history[0].comment := op.oldcomment;
  52. op.oldcomment := temp;
  53. END Do;
  54. PROCEDURE Format (v: StdView);
  55. VAR s: ARRAY 64 OF CHAR; d: Dates.Date; t: INTEGER;
  56. BEGIN
  57. t := v.history[0].time;
  58. Dates.DayToDate(v.history[0].date, d);
  59. Dates.DateToString(d, Dates.plainAbbreviated, s); v.cache := s$;
  60. Strings.IntToStringForm(v.history[0].snr, Strings.decimal, 4, "0", FALSE, s);
  61. v.cache := v.cache + " (" + s + ")"
  62. END Format;
  63. PROCEDURE FontContext (v: StdView): Fonts.Font;
  64. VAR c: Models.Context;
  65. BEGIN
  66. c := v.context;
  67. IF (c # NIL) & (c IS TextModels.Context) THEN
  68. RETURN c(TextModels.Context).Attr().font;
  69. ELSE
  70. RETURN Fonts.dir.Default()
  71. END;
  72. END FontContext;
  73. PROCEDURE CalcFP (t: TextModels.Model): INTEGER;
  74. CONST sglQuote = "'"; dblQuote = '"';
  75. VAR fp: INTEGER; rd: TextModels.Reader; ch, quoteChar: CHAR;
  76. BEGIN
  77. quoteChar := 0X; fp := 0;
  78. rd := t.NewReader(NIL); rd.ReadChar(ch);
  79. WHILE ~rd.eot DO
  80. IF ch = quoteChar THEN quoteChar := 0X;
  81. ELSIF (quoteChar = 0X) & ((ch = dblQuote) OR (ch = sglQuote)) THEN quoteChar := ch;
  82. END;
  83. IF (quoteChar = 0X) & (21X <= ch) & (ch # 8BX) & (ch # 8FX) & (ch # 0A0X) (* not in string literal *)
  84. OR (quoteChar # 0X) & (20X <= ch) (* within string literal *)
  85. THEN
  86. fp := SYSTEM.ROT(fp, 1) + 13 * ORD(ch);
  87. END;
  88. rd.ReadChar(ch);
  89. END;
  90. RETURN fp;
  91. END CalcFP;
  92. PROCEDURE Update (v: StdView; forcenew: BOOLEAN);
  93. VAR fp: INTEGER; i: INTEGER; ndays: INTEGER; d: Dates.Date; t: Dates.Time;
  94. BEGIN
  95. IF (v.context # NIL) & (v.context IS TextModels.Context) THEN
  96. fp := CalcFP(v.context(TextModels.Context).ThisModel());
  97. IF (fp # v.history[0].fprint) OR forcenew THEN
  98. Dates.GetDate(d); Dates.GetTime(t);
  99. ndays := Dates.Day(d);
  100. IF (ndays # v.history[0].date) OR forcenew THEN
  101. (* move down entries in history list *)
  102. i := maxHistoryEntries-1;
  103. WHILE i > 0 DO
  104. v.history[i] := v.history[i-1];
  105. DEC(i);
  106. END;
  107. v.history[0].comment := NIL;
  108. END;
  109. IF v.nentries < maxHistoryEntries THEN INC(v.nentries) END;
  110. INC(v.history[0].snr);
  111. v.history[0].fprint := fp;
  112. v.history[0].date := ndays;
  113. v.history[0].time := t.minute + t.hour*64;
  114. Format(v);
  115. Views.Update(v, Views.keepFrames);
  116. END;
  117. END;
  118. END Update;
  119. PROCEDURE (v: StdView) Externalize (VAR wr: Stores.Writer);
  120. VAR i, len: INTEGER;
  121. BEGIN
  122. Update(v, FALSE);
  123. v.Externalize^(wr);
  124. wr.WriteVersion(thisVersion);
  125. (*--wr.WriteLInt(v.snr);*)
  126. wr.WriteXInt(v.nentries);
  127. FOR i := 0 TO v.nentries-1 DO
  128. wr.WriteInt(v.history[i].fprint);
  129. wr.WriteInt(v.history[i].snr);
  130. wr.WriteInt(v.history[i].date);
  131. wr.WriteXInt(v.history[i].time);
  132. IF v.history[i].comment # NIL THEN
  133. len := LEN(v.history[i].comment$);
  134. wr.WriteXInt(len);
  135. wr.WriteXString(v.history[i].comment^);
  136. ELSE wr.WriteXInt(0);
  137. END
  138. END;
  139. END Externalize;
  140. PROCEDURE (v: StdView) Internalize (VAR rd: Stores.Reader);
  141. VAR version: INTEGER; format: BYTE; i, len: INTEGER;
  142. d: Dates.Date; t: Dates.Time;
  143. BEGIN
  144. v.Internalize^(rd);
  145. IF ~rd.cancelled THEN
  146. rd.ReadVersion(minVersion, thisVersion, version);
  147. IF ~rd.cancelled THEN
  148. IF version = origStampVersion THEN (* deal with old StdStamp format *)
  149. (* would like to calculate fingerprint, but hosting model not available at this time *)
  150. v.history[0].fprint := 0;
  151. v.history[0].snr := 1; v.nentries := 1;
  152. rd.ReadXInt(d.year); rd.ReadXInt(d.month); rd.ReadXInt(d.day);
  153. rd.ReadXInt(t.hour); rd.ReadXInt(t.minute); rd.ReadXInt(t.second);
  154. rd.ReadByte(format); (* format not used anymore *)
  155. v.history[0].date := Dates.Day(d);
  156. v.history[0].time := t.minute + t.hour*64;
  157. ELSE
  158. IF version = 1 THEN rd.ReadInt(v.history[0].snr) END; (* red text: to be removed soon *)
  159. rd.ReadXInt(v.nentries);
  160. FOR i := 0 TO v.nentries-1 DO
  161. rd.ReadInt(v.history[i].fprint);
  162. IF version > 1 THEN rd.ReadInt(v.history[i].snr)
  163. ELSIF (* (version = 1) & *) i > 0 THEN v.history[i].snr := v.history[i-1].snr - 1;
  164. END; (* red text: to be removed soon *)
  165. rd.ReadInt(v.history[i].date);
  166. rd.ReadXInt(v.history[i].time);
  167. rd.ReadXInt(len);
  168. IF len > 0 THEN
  169. NEW(v.history[i].comment, len + 1);
  170. rd.ReadXString(v.history[i].comment^);
  171. ELSE v.history[i].comment := NIL;
  172. END
  173. END;
  174. END;
  175. Format(v);
  176. END
  177. END
  178. END Internalize;
  179. PROCEDURE (v: StdView) CopyFromSimpleView (source: Views.View);
  180. VAR i: INTEGER;
  181. BEGIN
  182. (* v.CopyFrom^(source); *)
  183. WITH source: StdView DO
  184. (*--v.snr := source.snr;*)
  185. v.nentries := source.nentries;
  186. v.history := source.history;
  187. v.cache := source.cache;
  188. FOR i := 0 TO v.nentries - 1 DO
  189. IF source.history[i].comment # NIL THEN
  190. NEW(v.history[i].comment, LEN(source.history[i].comment$) + 1);
  191. v.history[i].comment^ := source.history[i].comment^$;
  192. END
  193. END
  194. END
  195. END CopyFromSimpleView;
  196. PROCEDURE (v: StdView) Restore (f: Views.Frame; l, t, r, b: INTEGER);
  197. VAR a: TextModels.Attributes; color: Ports.Color; c: Models.Context; font: Fonts.Font;
  198. asc, dsc, fw: INTEGER;
  199. BEGIN
  200. c := v.context;
  201. IF (c # NIL) & (c IS TextModels.Context) THEN
  202. a := v.context(TextModels.Context).Attr();
  203. font := a.font;
  204. color := a.color;
  205. ELSE font := Fonts.dir.Default(); color := Ports.black;
  206. END;
  207. font.GetBounds(asc, dsc, fw);
  208. f.DrawLine(f.l, asc + f.dot, f.r, asc + f.dot, 1, Ports.grey25 );
  209. f.DrawString(0, asc, color, v.cache, font);
  210. END Restore;
  211. PROCEDURE SizePref (v: StdView; VAR p: Properties.SizePref);
  212. VAR font: Fonts.Font; asc, dsc, w: INTEGER; d: Dates.Date; s: ARRAY 64 OF CHAR;
  213. BEGIN
  214. font := FontContext(v);
  215. font.GetBounds(asc, dsc, w);
  216. d.day := 28; d.month := 1; d.year := 2222; p.w := 0;
  217. WHILE d.month <= 12 DO
  218. Dates.DateToString(d, Dates.plainAbbreviated, s);
  219. s := s + " (0000)";
  220. w := font.StringWidth(s);
  221. IF w > p.w THEN p.w := w END;
  222. INC(d.month)
  223. END;
  224. p.h := asc + dsc;
  225. END SizePref;
  226. PROCEDURE (v: StdView) HandlePropMsg (VAR msg: Properties.Message);
  227. VAR font: Fonts.Font; asc, w: INTEGER;
  228. BEGIN
  229. WITH msg: Properties.Preference DO
  230. WITH msg: Properties.SizePref DO
  231. SizePref(v, msg)
  232. | msg: Properties.ResizePref DO
  233. msg.fixed := TRUE
  234. | msg: Properties.FocusPref DO
  235. msg.hotFocus := TRUE
  236. | msg: TextSetters.Pref DO
  237. font := FontContext(v);
  238. font.GetBounds(asc, msg.dsc, w);
  239. ELSE
  240. END
  241. ELSE
  242. END
  243. END HandlePropMsg;
  244. PROCEDURE NewRuler (): TextRulers.Ruler;
  245. CONST mm = Ports.mm;
  246. VAR r: TextRulers.Ruler;
  247. BEGIN
  248. r := TextRulers.dir.New(NIL);
  249. TextRulers.SetRight(r, 140 * mm);
  250. TextRulers.AddTab(r, 15 * mm); TextRulers.AddTab(r, 35 * mm); TextRulers.AddTab(r, 75 * mm);
  251. RETURN r
  252. END NewRuler;
  253. PROCEDURE ShowHistory (v: StdView);
  254. VAR text: TextModels.Model; f: TextMappers.Formatter;
  255. i: INTEGER; d: Dates.Date; s: ARRAY 64 OF CHAR;
  256. tv: TextViews.View; attr: TextModels.Attributes;
  257. BEGIN
  258. text := TextModels.dir.New();
  259. f.ConnectTo(text);
  260. attr := f.rider.attr;
  261. f.rider.SetAttr(TextModels.NewStyle(attr, {Fonts.italic}));
  262. f.WriteString("seq nr."); f.WriteTab;
  263. f.WriteString("fingerprint"); f.WriteTab;
  264. f.WriteString("date and time"); f.WriteTab;
  265. f.WriteString("comment"); f.WriteLn;
  266. f.rider.SetAttr(attr); f.WriteLn;
  267. (*--n := v.snr;*)
  268. FOR i := 0 TO v.nentries-1 DO
  269. f.WriteIntForm(v.history[i].snr, 10, 4, "0", FALSE);
  270. (*--DEC(n);*)
  271. f.WriteTab;
  272. f.WriteIntForm(v.history[i].fprint, TextMappers.hexadecimal, 8, "0", FALSE);
  273. f.WriteTab;
  274. Dates.DayToDate(v.history[i].date, d);
  275. Dates.DateToString(d, Dates.plainAbbreviated, s);
  276. f.WriteString(s);
  277. f.WriteString(" ");
  278. f.WriteIntForm(v.history[i].time DIV 64, 10, 2, "0", FALSE);
  279. f.WriteString(":");
  280. f.WriteIntForm(v.history[i].time MOD 64, 10, 2, "0", FALSE);
  281. IF v.history[i].comment # NIL THEN
  282. f.WriteTab;
  283. f.WriteString( v.history[i].comment^);
  284. END;
  285. f.WriteLn;
  286. END;
  287. tv := TextViews.dir.New(text);
  288. tv.SetDefaults(NewRuler(), TextViews.dir.defAttr);
  289. tv.ThisController().SetOpts({Containers.noFocus, Containers.noCaret});
  290. Views.OpenAux(tv, "History");
  291. END ShowHistory;
  292. PROCEDURE Track (v: StdView; f: Views.Frame; x, y: INTEGER; buttons: SET);
  293. VAR c: Models.Context; w, h: INTEGER; isDown, in, in0: BOOLEAN; m: SET;
  294. BEGIN
  295. c := v.context; c.GetSize(w, h); in0 := FALSE; in := TRUE;
  296. REPEAT
  297. IF in # in0 THEN
  298. f.MarkRect(0, 0, w, h, Ports.fill, Ports.invert, Ports.show); in0 := in
  299. END;
  300. f.Input(x, y, m, isDown);
  301. in := (0 <= x) & (x < w) & (0 <= y) & (y < h)
  302. UNTIL ~isDown;
  303. IF in0 THEN
  304. f.MarkRect(0, 0, w, h, Ports.fill, Ports.invert, Ports.hide);
  305. IF Controllers.modify IN m THEN
  306. IF v.history[0].comment # NIL THEN comment.s := v.history[0].comment^$;
  307. ELSE comment.s := "";
  308. END;
  309. StdCmds.OpenToolDialog("Std/Rsrc/Stamps", "Comment");
  310. ELSE ShowHistory(v);
  311. END
  312. END
  313. END Track;
  314. PROCEDURE (v: StdView) HandleCtrlMsg (
  315. f: Views.Frame; VAR msg: Controllers.Message; VAR focus: Views.View);
  316. BEGIN
  317. WITH msg: Controllers.TrackMsg DO
  318. Track(v, f, msg.x, msg.y, msg.modifiers)
  319. | msg: Controllers.PollCursorMsg DO
  320. msg.cursor := Ports.refCursor
  321. ELSE
  322. END
  323. END HandleCtrlMsg;
  324. (* ------------ programming interface: ---------------------- *)
  325. PROCEDURE GetFirstInText* (t: TextModels.Model): Views.View;
  326. VAR r: TextModels.Reader; v: Views.View;
  327. BEGIN
  328. IF t # NIL THEN
  329. r := t.NewReader(NIL);
  330. REPEAT r.ReadView(v) UNTIL (v = NIL) OR (v IS StdView);
  331. RETURN v;
  332. ELSE RETURN NIL;
  333. END;
  334. END GetFirstInText;
  335. PROCEDURE IsStamp* (v: Views.View): BOOLEAN;
  336. BEGIN
  337. RETURN v IS StdView;
  338. END IsStamp;
  339. PROCEDURE GetInfo* (v: Views.View; VAR snr, historylen: INTEGER);
  340. BEGIN
  341. ASSERT(v IS StdView, 20);
  342. WITH v: StdView DO
  343. snr := v.history[0].snr; historylen := v.nentries;
  344. END
  345. END GetInfo;
  346. PROCEDURE GetData* (v: Views.View; entryno: INTEGER;
  347. VAR fprint: INTEGER; VAR date: Dates.Date; VAR time: Dates.Time);
  348. BEGIN
  349. ASSERT(v IS StdView, 20);
  350. WITH v: StdView DO
  351. IF entryno <= v.nentries THEN
  352. fprint := v.history[entryno].fprint;
  353. Dates.DayToDate(v.history[entryno].date, date);
  354. time.minute := v.history[entryno].time MOD 64;
  355. time.minute := v.history[entryno].time DIV 64;
  356. time.second := 0;
  357. END
  358. END
  359. END GetData;
  360. (** Insert new history entry with comment in v. *)
  361. PROCEDURE Stamp* (v: Views.View; comment: ARRAY OF CHAR);
  362. BEGIN
  363. ASSERT(v IS StdView, 20);
  364. WITH v: StdView DO
  365. Update(v, TRUE);
  366. NEW(v.history[0].comment, LEN(comment$) + 1);
  367. v.history[0].comment^ := comment$;
  368. END
  369. END Stamp;
  370. PROCEDURE New* (): Views.View;
  371. VAR v: StdView; d: Dates.Date; t: Dates.Time;
  372. BEGIN
  373. NEW(v); v.history[0].snr := 0; v.nentries := 0;
  374. v.history[0].fprint := 0;
  375. Dates.GetDate(d); Dates.GetTime(t);
  376. v.history[0].date := Dates.Day(d);
  377. v.history[0].time := t.minute + t.hour*64;
  378. Format(v);
  379. RETURN v;
  380. END New;
  381. PROCEDURE SetComment*;
  382. VAR v: Views.View; op: SetCmtOp;
  383. BEGIN
  384. v := GetFirstInText(TextViews.FocusText());
  385. IF v # NIL THEN
  386. WITH v: StdView DO
  387. NEW(op); op.stamp := v;
  388. NEW(op.oldcomment, LEN(comment.s$) + 1);
  389. op.oldcomment^ := comment.s$;
  390. Views.Do(v, setCommentKey, op);
  391. END
  392. END
  393. END SetComment;
  394. PROCEDURE Deposit*;
  395. BEGIN
  396. Views.Deposit(New())
  397. END Deposit;
  398. END StdStamps.