MODULE ObxViews14;
(**
project = "BlackBox"
organization = "www.oberon.ch"
contributors = "Oberon microsystems"
version = "System/Rsrc/About"
copyright = "System/Rsrc/About"
license = "Docu/BB-License"
purpose = "Same as ObxViews13, but interfaces and implementations separated,
and operation directly in Insert procedure"
changes = ""
issues = ""
**)
IMPORT Fonts, Ports, Stores, Models, Views, Controllers, Properties;
CONST d = 20 * Ports.point;
TYPE
Model* = POINTER TO ABSTRACT RECORD (Models.Model) END;
ModelDirectory* = POINTER TO ABSTRACT RECORD END;
View* = POINTER TO ABSTRACT RECORD (Views.View) END;
Directory* = POINTER TO ABSTRACT RECORD END;
StdModel = POINTER TO RECORD (Model)
i: INTEGER; (* position of next free slot in string *)
s: ARRAY 256 OF CHAR (* string *)
END;
StdModelDirectory = POINTER TO RECORD (ModelDirectory) END;
StdView = POINTER TO RECORD (View)
model: Model
END;
StdDirectory = POINTER TO RECORD (Directory) END;
PasteCharOp = POINTER TO RECORD (Stores.Operation)
model: StdModel;
char: CHAR;
do: BOOLEAN
END;
VAR
mdir-: ModelDirectory;
dir-: Directory;
(* Model *)
PROCEDURE (m: Model) Insert* (char: CHAR), NEW, ABSTRACT;
PROCEDURE (m: Model) Remove*, NEW, ABSTRACT;
PROCEDURE (m: Model) GetString* (OUT s: ARRAY OF CHAR), NEW, ABSTRACT;
(* ModelDirectory *)
PROCEDURE (d: ModelDirectory) New* (): Model, NEW, ABSTRACT;
(* PasteCharOp *)
PROCEDURE (op: PasteCharOp) Do;
VAR m: StdModel; msg: Models.UpdateMsg;
BEGIN
m := op.model;
IF op.do THEN (* do operation's transformation *)
m.s[m.i] := op.char; INC(m.i);
ELSE (* undo operation's transformation *)
DEC(m.i) (* remove character from string *)
END;
m.s[m.i] := 0X;
op.do := ~op.do; (* toggle between "do" and "undo" *)
Models.Broadcast(m, msg) (* update all views on this model *)
END Do;
(* StdModel *)
PROCEDURE (m: StdModel) Internalize (VAR rd: Stores.Reader);
VAR version: INTEGER;
BEGIN
rd.ReadVersion(0, 0, version);
IF ~rd.cancelled THEN
rd.ReadInt(m.i); rd.ReadString(m.s)
END
END Internalize;
PROCEDURE (m: StdModel) Externalize (VAR wr: Stores.Writer);
BEGIN
wr.WriteVersion(0);
wr.WriteInt(m.i); wr.WriteString(m.s)
END Externalize;
PROCEDURE (m: StdModel) CopyFrom (source: Stores.Store);
BEGIN
WITH source: StdModel DO
m.i := source.i; m.s := source.s
END
END CopyFrom;
PROCEDURE (m: StdModel) Insert (char: CHAR);
VAR op: PasteCharOp;
BEGIN
NEW(op); op.model := m; op.char := char; op.do := TRUE;
Models.Do(m, "insertion", op)
END Insert;
PROCEDURE (m: StdModel) Remove;
VAR msg: Models.UpdateMsg;
BEGIN
DEC(m.i); m.s[m.i] := 0X;
Models.Broadcast(m, msg) (* update all views on this model *)
END Remove;
PROCEDURE (m: StdModel) GetString (OUT s: ARRAY OF CHAR);
BEGIN
s := m.s$
END GetString;
(* StdModelDirectory *)
PROCEDURE (d: StdModelDirectory) New (): Model;
VAR m: StdModel;
BEGIN
NEW(m); m.s := "";m.i := 0; RETURN m
END New;
(* Directory *)
PROCEDURE (d: Directory) New* (m: Model): View, NEW, ABSTRACT;
(* StdView *)
PROCEDURE (v: StdView) Internalize (VAR rd: Stores.Reader);
VAR version: INTEGER; st: Stores.Store;
BEGIN
rd.ReadVersion(0, 0, version);
IF ~rd.cancelled THEN
rd.ReadStore(st);
IF st IS Model THEN
v.model := st(Model)
ELSE
(* concrete model implementation couldn't be loaded->
an alien store was created *)
rd.TurnIntoAlien(Stores.alienComponent)
(* internalization of v is cancelled *)
END
END
END Internalize;
PROCEDURE (v: StdView) Externalize (VAR wr: Stores.Writer);
BEGIN
wr.WriteVersion(0);
wr.WriteStore(v.model)
END Externalize;
PROCEDURE (v: StdView) CopyFromModelView (source: Views.View; model: Models.Model);
BEGIN
WITH source: StdView DO
v.model := model(Model)
END
END CopyFromModelView;
PROCEDURE (v: StdView) Restore (f: Views.Frame; l, t, r, b: INTEGER);
VAR s: ARRAY 256 OF CHAR;
BEGIN
v.model.GetString(s);
f.DrawString(d, d, Ports.black, s, Fonts.dir.Default())
END Restore;
PROCEDURE (v: StdView) ThisModel (): Models.Model;
BEGIN
RETURN v.model
END ThisModel;
PROCEDURE (v: StdView) HandleModelMsg (VAR msg: Models.Message);
BEGIN
Views.Update(v, Views.keepFrames) (* restore v in any frame that displays it *)
END HandleModelMsg;
PROCEDURE (v: StdView) HandleCtrlMsg (f: Views.Frame;
VAR msg: Controllers.Message;
VAR focus: Views.View);
BEGIN
WITH msg: Controllers.EditMsg DO
IF msg.op = Controllers.pasteChar THEN
v.model.Insert(msg.char)
END
ELSE (* ignore other messages *)
END
END HandleCtrlMsg;
PROCEDURE (v:StdView) HandlePropMsg (VAR msg: Properties.Message);
BEGIN
WITH msg: Properties.SizePref DO
IF (msg.w = Views.undefined) OR (msg.h = Views.undefined) THEN
msg.w := 10 * d; msg.h := 2 *d
END
| msg: Properties.FocusPref DO
msg.setFocus := TRUE
ELSE
END
END HandlePropMsg;
(* StdDirectory *)
PROCEDURE (d: StdDirectory) New* (m: Model): View;
VAR v: StdView;
BEGIN
ASSERT(m # NIL, 20);
NEW(v); v.model := m; Stores.Join(v, m);
RETURN v
END New;
PROCEDURE Deposit*;
VAR v: View;
BEGIN
v := dir.New(mdir.New());
Views.Deposit(v)
END Deposit;
PROCEDURE SetModelDir* (d: ModelDirectory);
BEGIN
ASSERT(d # NIL, 20);
mdir := d
END SetModelDir;
PROCEDURE SetDir* (d: Directory);
BEGIN
ASSERT(d # NIL, 20);
dir := d
END SetDir;
PROCEDURE Init;
VAR md: StdModelDirectory; d: StdDirectory;
BEGIN
NEW(md); mdir := md;
NEW(d); dir := d
END Init;
BEGIN
Init
END ObxViews14.