GraphTable.mesa, Copyright © 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Sweetsun Chen, November 27, 1985 11:14:12 pm PST
DIRECTORY
Containers USING [ChildXBound, ChildYBound],
Convert USING [RopeFromInt],
Graph USING [Entity, EntityGroup, EntityGroupList, EntityList, GraphHandle, GraphProc, NestedEntities, NestedEntitiesList, ROPE, Text, Texts, Viewer],
GraphPrivate USING [CallWithLock, RemoveEntity, RemoveText, ShowEntity, ShowText, UserEditAllowed],
GraphUtil USING [BlinkMsg, ControllerViewerExits, HandleNotNil],
InputFocus USING [SetInputFocus],
Rope USING [Concat, Fetch, IsEmpty, Length],
TiogaFileOps USING [AddLooks, CreateRoot, InsertAsLastChild, InsertNode, Ref, SetContents, Store],
TiogaButtons USING [CreateButton, CreateButtonFromNode, CreateViewer, LoadViewer, MarkViewerNotEdited, TiogaButton, TiogaButtonList, TiogaButtonProc],
TiogaOps USING [Break, FirstChild, GetProp, GetRope, InsertRope, LastChild, Lock, LockSel, Nest, Next, Ref, RestoreSelA, SaveSelA, SelectPoint, SetSelection, StepForward, Unlock, UnlockSel, ViewerDoc],
ViewerTools USING [SetContents];
GraphTable: CEDAR PROGRAM
IMPORTS Containers, Convert, GraphPrivate, GraphUtil, Rope, TiogaFileOps, TiogaOps, TiogaButtons, ViewerTools
EXPORTS GraphPrivate = { OPEN Graph, GraphPrivate;
GraphButtonData: TYPE = REF GraphButtonDataRec;
GraphButtonDataRec: TYPE = RECORD[
handle: GraphHandle ← NIL,
ref: REF ANYNIL
];
MakeTable: PUBLIC PROC [handle: GraphHandle, file: ROPE, sx, sy: INTEGER] = {
called by NewController, which should have made sure the following not nil: handle, handle.controller, etc.
IF GraphUtil.HandleNotNil[handle] THEN { OPEN handle;
controller.table ← TiogaButtons.CreateViewer[
info: [
wx: sx, wy: sy, ww: 1000, wh: 1000,
menu: NIL,
parent: controller.viewer,
scrollable: TRUE,
border: FALSE,
caption: FALSE
]];
Containers.ChildXBound[controller.viewer, controller.table];
Containers.ChildYBound[controller.viewer, controller.table];
MakeTableFile[handle, file];
TiogaButtons.LoadViewer[controller.table, file];
CreateButtons[handle];
TiogaOps.Jump[controller.table, [controller.textsParent, 0]];
};
}; -- MakeTable
MakeTableFile: PROC [handle: GraphHandle, tableFile: ROPE] = {
root, prev: TiogaFileOps.Ref;
IF GraphUtil.HandleNotNil[handle] THEN { OPEN handle;
root ← TiogaFileOps.CreateRoot[];
prev ← TextsTable[handle, root];
FOR egl: EntityGroupList ← entityGroupList, egl.rest UNTIL egl = NIL DO
prev ← NETable[handle, egl.first.ys, root, root, prev];
ENDLOOP;
TiogaFileOps.Store[root, tableFile];
};
}; -- MakeTableFile
NextNode: PROC [root, prev: TiogaFileOps.Ref, rope: ROPE, child: BOOL, look: ROPENIL] RETURNS [new: TiogaFileOps.Ref] = {
new ← TiogaFileOps.InsertNode[prev, child];
TiogaFileOps.SetContents[new, rope];
IF NOT look.IsEmpty[] THEN FOR i: INT IN [0..look.Length[]) DO
TiogaFileOps.AddLooks[new, 0, rope.Length[], look.Fetch[i], root];
ENDLOOP;
}; -- NextNode
LastChild: PROC [root, parent, prev: TiogaFileOps.Ref, rope: ROPE, look: ROPENIL] RETURNS [new: TiogaFileOps.Ref] = {
new ← TiogaFileOps.InsertAsLastChild[parent, prev];
TiogaFileOps.SetContents[new, rope];
IF NOT look.IsEmpty[] THEN FOR i: INT IN [0..look.Length[]) DO
TiogaFileOps.AddLooks[new, 0, rope.Length[], look.Fetch[i], root];
ENDLOOP;
}; -- LastChild
TextsTable: PROC [handle: GraphHandle, root: TiogaFileOps.Ref] RETURNS [new: TiogaFileOps.Ref] = {
new ← NextNode[root, root, "", TRUE];
new ← NextNode[root, new, "Texts", FALSE, "lb"]; -- texts parent
new ← NextNode[root, new, "", TRUE]; -- leading blank line
FOR ts: Texts ← handle.allTexts, ts.rest UNTIL ts = NIL DO
t: Text ← ts.first; -- error if nil.
new ← NextNode[
root: root, prev: new,
rope: IF t.text = NIL THEN Convert.RopeFromInt[t.id] ELSE t.text,
child: FALSE,
look: NIL
];
ENDLOOP;
}; -- TextsTable
EntityListTable: PROC [handle: GraphHandle, entityList: EntityList, root, parent: TiogaFileOps.Ref] RETURNS [new: TiogaFileOps.Ref] = {
new ← parent; -- which is also the previous node.
IF entityList # NIL THEN new ← NextNode[root, parent, "", TRUE];
FOR el: EntityList ← entityList, el.rest UNTIL el = NIL DO
entity: Entity ← el.first; -- error if nil.
new ← LastChild[root: root, parent: parent, prev: new,
rope: IF entity.name.IsEmpty[] AND entity.comment.IsEmpty[]
THEN Convert.RopeFromInt[entity.id]
ELSE entity.name.Concat[entity.comment],
look: NIL
];
ENDLOOP;
}; -- EntityListTable
NETable: PROC [handle: GraphHandle, ne: NestedEntities, root, parent, prev: TiogaFileOps.Ref] RETURNS [new: TiogaFileOps.Ref] = {
new ← prev;
IF ne # NIL THEN {
topLevel: BOOL ← parent = root;
neNode: TiogaFileOps.Ref;
heading
new ← LastChild[root: root, parent: parent, prev: prev, rope: "", look: NIL];
neNode ← new ← NextNode[root: root, prev: new, -- ne.node
rope: ne.name.Concat[ne.comment],
child: FALSE,
look: IF topLevel THEN "lb" ELSE "b"
];
now its entity list and children.
new ← EntityListTable[handle, ne.entityList, root, neNode];
FOR nel: NestedEntitiesList ← ne.children, nel.rest UNTIL nel = NIL DO
new ← NETable[handle, nel.first, root, neNode, new];
ENDLOOP;
};
}; -- NETable
CreateButtons: PROC [handle: GraphHandle] = { OPEN handle;
root: TiogaOps.Ref ← TiogaOps.ViewerDoc[controller.table];
prev: TiogaOps.Ref;
TiogaOps.Lock[root];
TiogaOps.SaveSelA[];
prev ← TextsButtons[handle, root];
FOR egl: EntityGroupList ← entityGroupList, egl.rest UNTIL egl = NIL DO
prev ← NEButtons[handle, egl.first.ys, root, root, prev];
ENDLOOP;
TiogaOps.Unlock[root];
TiogaOps.RestoreSelA[];
}; -- CreateButtons
TextsButtons: PROC [handle: GraphHandle, root: TiogaOps.Ref] RETURNS [last: TiogaOps.Ref] = { OPEN handle;
last ← TiogaOps.FirstChild[root];
controller.textsParent ← last ← TiogaOps.StepForward[last];
last ← TiogaOps.StepForward[last];
FOR ts: Texts ← handle.allTexts, ts.rest UNTIL ts = NIL DO
t: Text ← ts.first; -- error if nil.
last ← TiogaOps.StepForward[last];
[] ← TiogaButtons.CreateButtonFromNode[node: last,
proc: TextButtonProc,
clientData: NEW[GraphButtonDataRec ← [handle, t]]
];
ENDLOOP;
}; -- TextsButtons
EntityListButtons: PROC [handle: GraphHandle, entityList: EntityList, root, parent: TiogaOps.Ref] RETURNS [last: TiogaOps.Ref] = {
last ← parent; -- which is also the previous node.
IF entityList # NIL THEN last ← TiogaOps.StepForward[last];
FOR el: EntityList ← entityList, el.rest UNTIL el = NIL DO
entity: Entity ← el.first; -- error if nil.
last ← TiogaOps.StepForward[last];
[] ← TiogaButtons.CreateButtonFromNode[node: last,
proc: EntityButtonProc,
clientData: NEW[GraphButtonDataRec ← [handle, entity]]
];
ENDLOOP;
}; -- EntityListButtons
NEButtons: PROC [handle: GraphHandle, ne: NestedEntities, root, parent, prev: TiogaOps.Ref] RETURNS [last: TiogaOps.Ref] = {
last ← prev;
IF ne # NIL THEN {
topLevel: BOOL ← parent = root;
last ← TiogaOps.StepForward[last];
ne.node ← last ← TiogaOps.StepForward[last];
last ← EntityListButtons[handle, ne.entityList, root, ne.node];
FOR nel: NestedEntitiesList ← ne.children, nel.rest UNTIL nel = NIL DO
last ← NEButtons[handle, nel.first, root, ne.node, last];
ENDLOOP;
};
}; -- NEButtons
EntityGroupButtonProc: TiogaButtons.TiogaButtonProc = { -- noop for now
handle: GraphHandle ← NARROW[ViewerOps.FetchProp[parent, $GraphController]];
group: EntityGroup ← NARROW[clientData];
some checking might be necessary.
SetIntField[controller.groupId, group.id];
Control[handle, resume, $Group];
SELECT moustButton FROM
red => IF control THEN Control[handle, display, $Group];
blue => IF control THEN Control[handle, remove, $Group];
ENDCASE;
}; -- EntityGroupButtonProc
NestedEntitiesButtonProc: TiogaButtons.TiogaButtonProc = { -- noop for now.
}; -- NestedEntitiesButtonProc
EntityButtonProc: TiogaButtons.TiogaButtonProc = {
data: GraphButtonData ← NARROW[clientData];
proc: GraphProc = {
entity: Entity ← NARROW[data.ref];
SELECT mouseButton FROM
red => {
ViewerTools.SetContents[handle.controller.entityId, Convert.RopeFromInt[entity.id]];
ShowEntity[handle, entity];
};
blue => RemoveEntity[handle, entity];
ENDCASE;
};
IF UserEditAllowed[data.handle] THEN CallWithLock[data.handle, proc];
}; -- EntityButtonProc
TextButtonProc: TiogaButtons.TiogaButtonProc = {
data: GraphButtonData ← NARROW[clientData];
proc: GraphProc = {
t: Text ← NARROW[data.ref];
SELECT mouseButton FROM
red => {
ViewerTools.SetContents[handle.controller.textId, Convert.RopeFromInt[t.id]];
ShowText[handle, t];
};
blue => RemoveText[handle, t];
ENDCASE;
};
CallWithLock[data.handle, proc];
}; -- EntityButtonProc
AddTextButton: PUBLIC PROC [handle: GraphHandle, text: Text] = {
IF GraphUtil.ControllerViewerExits[handle] AND handle.controller.table # NIL AND text # NIL THEN {
root: TiogaOps.Ref ← TiogaOps.ViewerDoc[handle.controller.table];
TiogaOps.Lock[root];
TiogaOps.SelectPoint[handle.controller.table,
[TiogaOps.LastChild[handle.controller.textsParent], -1]];
TiogaOps.LockSel[];
TiogaOps.Break[];
TiogaOps.InsertRope[
IF text.text = NIL THEN Convert.RopeFromInt[text.id] ELSE text.text];
TiogaOps.UnlockSel[];
TiogaOps.Unlock[root];
[] ← TiogaButtons.CreateButtonFromNode[
node: TiogaOps.LastChild[handle.controller.textsParent], start: , end: ,
proc: TextButtonProc,
clientData: NEW[GraphButtonDataRec ← [handle, text]]
];
};
}; -- AddTextButton
AddEntityButton: PUBLIC PROC [handle: GraphHandle, entity: Entity] = {
IF GraphUtil.ControllerViewerExits[handle] AND handle.controller.table # NIL AND entity # NIL THEN {
root: TiogaOps.Ref ← TiogaOps.ViewerDoc[handle.controller.table];
group: EntityGroup ← entity.group;
TiogaOps.Lock[root];
TiogaOps.SelectPoint[handle.controller.table,
[TiogaOps.LastChild[group.ys.node], -1]];
TiogaOps.LockSel[];
TiogaOps.Break[];
TiogaOps.Nest[];
TiogaOps.InsertRope[
IF entity.name.IsEmpty[] AND entity.comment.IsEmpty[] THEN Convert.RopeFromInt[entity.id]
ELSE entity.name.Concat[entity.comment]];
TiogaOps.UnlockSel[];
TiogaOps.Unlock[root];
[] ← TiogaButtons.CreateButtonFromNode[
node: TiogaOps.LastChild[group.ys.node], start: , end: ,
proc: EntityButtonProc,
clientData: NEW[GraphButtonDataRec ← [handle, entity]]
];
};
}; -- AddEntityButton
AddGroupButton: PUBLIC PROC[handle: GraphHandle, entityGroup: EntityGroup] = {
IF GraphUtil.ControllerViewerExits[handle] AND handle.controller.table # NIL AND entityGroup # NIL THEN {
b: TiogaButtons.TiogaButton ← TiogaButtons.CreateButton[
viewer: handle.controller.table,
rope: entityGroup.ys.name.Concat[entityGroup.ys.comment],
looks: "b",
proc: NestedEntitiesButtonProc,
clientData: NEW[GraphButtonDataRec ← [handle, entityGroup.ys]]
];
entityGroup.ys.node ← TiogaOps.LastChild[TiogaOps.ViewerDoc[handle.controller.table]]
};
}; -- AddGroupButton
UpdateTextButton: PUBLIC PROC [handle: GraphHandle, text: Text] = {
replace the rope of a text button
IF GraphUtil.ControllerViewerExits[handle] AND handle.controller.table # NIL AND text # NIL THEN {
root: TiogaOps.Ref ← TiogaOps.ViewerDoc[handle.controller.table];
self: TiogaOps.Ref ← NIL;
TiogaOps.Lock[root];
FOR n: TiogaOps.Ref ← TiogaOps.FirstChild[handle.controller.textsParent], TiogaOps.Next[n] UNTIL n = NIL DO
list: TiogaButtons.TiogaButtonList ← NIL;
tb: TiogaButtons.TiogaButton;
gbd: GraphButtonData;
tt: Text;
ref: REF ANY ← TiogaOps.GetProp[n, $TiogaButtonList];
IF ref = NIL THEN LOOP;
IF ISTYPE[ref, TiogaButtons.TiogaButtonList] THEN list ← NARROW[ref] ELSE LOOP;
IF (tb ← list.first) = NIL THEN LOOP;
IF (gbd ← NARROW[tb.clientData]) = NIL THEN LOOP;
IF gbd.ref = NIL THEN LOOP;
IF ISTYPE[gbd.ref, Text] THEN {
tt ← NARROW[gbd.ref];
IF tt = text THEN {self ← n; EXIT};
};
ENDLOOP;
IF self = NIL THEN GraphUtil.BlinkMsg["Can't find the text on table."]
ELSE {
TiogaOps.SaveSelA[];
TiogaOps.SetSelection[viewer: handle.controller.table,
start: [self, 0], end: [self, TiogaOps.GetRope[self].Length[]], level: char,
caretBefore: TRUE, pendingDelete: TRUE, which: primary];
TiogaOps.LockSel[];
TiogaOps.InsertRope[
IF text.text.IsEmpty[] THEN Convert.RopeFromInt[text.id] ELSE text.text];
TiogaOps.UnlockSel[];
TiogaButtons.MarkViewerNotEdited[root];
};
TiogaOps.RestoreSelA[];
TiogaOps.Unlock[root];
};
}; -- UpdateTextButton
UpdateEntityButton: PUBLIC PROC [handle: GraphHandle, entity: Entity] = {
replace the rope of an entity button
IF GraphUtil.ControllerViewerExits[handle] AND handle.controller.table # NIL AND entity # NIL THEN {
root: TiogaOps.Ref ← TiogaOps.ViewerDoc[handle.controller.table];
self: TiogaOps.Ref ← NIL;
TiogaOps.Lock[root];
FOR n: TiogaOps.Ref ← TiogaOps.FirstChild[entity.parent.node], TiogaOps.Next[n] UNTIL n = NIL DO
list: TiogaButtons.TiogaButtonList ← NIL;
tb: TiogaButtons.TiogaButton;
gbd: GraphButtonData;
te: Entity;
ref: REF ANY ← TiogaOps.GetProp[n, $TiogaButtonList];
IF ref = NIL THEN LOOP;
IF ISTYPE[ref, TiogaButtons.TiogaButtonList] THEN list ← NARROW[ref] ELSE LOOP;
IF (tb ← list.first) = NIL THEN LOOP;
IF (gbd ← NARROW[tb.clientData]) = NIL THEN LOOP;
IF gbd.ref = NIL THEN LOOP;
IF ISTYPE[gbd.ref, Entity] THEN {
te ← NARROW[gbd.ref];
IF te = entity THEN {self ← n; EXIT};
};
ENDLOOP;
IF self = NIL THEN GraphUtil.BlinkMsg["Can't find the entity on table."]
ELSE {
TiogaOps.SaveSelA[];
TiogaOps.SetSelection[viewer: handle.controller.table,
start: [self, 0], end: [self, TiogaOps.GetRope[self].Length[]], level: char,
caretBefore: TRUE, pendingDelete: TRUE, which: primary];
TiogaOps.LockSel[];
TiogaOps.InsertRope[
IF entity.name.IsEmpty[] AND entity.comment.IsEmpty[] THEN Convert.RopeFromInt[entity.id]
ELSE entity.name.Concat[entity.comment]
];
TiogaOps.UnlockSel[];
TiogaButtons.MarkViewerNotEdited[root];
};
TiogaOps.RestoreSelA[];
TiogaOps.Unlock[root];
};
}; -- UpdateEntityButton
}.
LOG.
SChen, created at October 9, 1985 6:57:10 pm PDT.