YodelRootImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Yodel: Button-style interface
Bob Hagmann July 9, 1985 9:11:34 am PDT
Carl Hauser, February 13, 1986 12:03:33 pm PST
DIRECTORY
AlpineEnvironment USING[ Property],
AlpineFile USING [ PropertySet],
Atom USING[ GetPName ],
Buttons USING[ Button, ButtonProc, Create, Destroy, SetDisplayStyle ],
Commander USING[ CommandProc, Register ],
Containers USING[ ChildXBound, ChildYBound, Create ],
IO,
Labels USING[ Create ],
MBQueue USING[ Create, CreateButton, Queue ],
Process,
Rope,
Rules USING[ Create ],
TypeScript USING[ Create ],
UserProfile USING[ CallWhenProfileChanges, ListOfTokens, ProfileChangedProc ],
ViewerClasses USING[ Viewer ],
ViewerIO USING[ CreateViewerStreams ],
ViewerOps USING[ ComputeColumn, DestroyViewer, MoveViewer, SetOpenHeight ],
ViewerTools USING[ GetContents, GetSelectedViewer, MakeNewTextViewer, SetContents, SelPosRec, SetSelection],
YodelData;
YodelRootImpl: CEDAR MONITOR LOCKS d USING d: MyData
IMPORTS Atom, Buttons, Commander, Containers, IO, Labels,MBQueue, Process, Rope, Rules, TypeScript, UserProfile, ViewerIO, ViewerOps, ViewerTools, YodelData
EXPORTS YodelData
NamePrefixes: LIST OF ROPE ← NIL;
defaultNamePrefixes:
LIST
OF
ROPE =
LIST[
"[Luther.Alpine]",
"[Ebbetts.Alpine]",
"[Ivy]",
"[Indigo]",
"[Cyan]",
""
];
PropertySetToRopeArray:
PUBLIC
ARRAY [0..NumberOfAlpineProperties)
OF PropertySetToRope ← [
[byteLength, "byteLength"],
[createTime, "createTime"],
[highWaterMark, "highWaterMark"],
[modifyAccess, "modifyAccess"],
[owner, "owner"],
[readAccess, "readAccess"],
[stringName, "stringName"],
[version, "version"]
];
******** Enquiry operations ********
Create: Commander.CommandProc = {
[exec: ExecHandle, clientData: REF ANY ← NIL] RETURNS[ok: BOOLEAN ← TRUE]
d: MyData = NEW[MyDataObject];
this is the container that includes all the other containers
v: ViewerClasses.Viewer = Containers.Create[
info: [name: "Yodel", column: left, scrollable: FALSE, iconic: TRUE]];
TRUSTED {Process.InitializeCondition[@d.condition, Process.MsecToTicks[250]];};
d.DelVerCount ← 1;
BEGIN
kludge to find max button sizes!
temp1: Buttons.Button = Buttons.Create[
info: [name: "Dest Server:", parent: v, border:
FALSE,
wx: 0, wy: 0],
proc: NIL, clientData: d, fork: FALSE, paint: FALSE];
temp2: Buttons.Button = Buttons.Create[
info: [name: "highWaterMark", parent: v, border:
FALSE,
wx: 0, wy: 0],
proc: NIL, clientData: d, fork: FALSE, paint: FALSE];
d.q ← MBQueue.Create[];
d.maxW ← temp1.ww;
d.buttH ← temp1.wh;
d.maxBW ← temp2.ww;
Buttons.Destroy[temp1];
Buttons.Destroy[temp2];
END;
start displaying only these two properties
d.displayProperties[byteLength] ← TRUE;
d.displayProperties[createTime] ← TRUE;
build viewer for "Level" menu
d.topChild ← CreateSelector[name: "Level:",
values: LIST[$User, $FileProperties, $OwnerProperties, $Administrator, $STOP],
change: ChangeLevel,
clientData: d,
viewer: v,
x: 2, y: 1].child;
create type script; it will be bound at the end of CreateButtons
under all the menus
d.script ← TypeScript.Create[
info: [parent: v, wh: v.ch - (d.topChild.wy + d.topChild.wh + 2), ww: v.cw,
border: FALSE,
wy: d.topChild.wy + d.topChild.wh + 2, wx: 0] ];
Containers.ChildXBound[v, d.script];
Containers.ChildYBound[v, d.script];
[in: d.in, out: d.out] ← ViewerIO.CreateViewerStreams[NIL, d.script];
CreateButtons[d, v];
};
ChangeLevel:
PROC[parent: ViewerClasses.Viewer, clientData:
REF
ANY, value:
ATOM] =
BEGIN
d: MyData = NARROW[clientData];
p: ViewerClasses.Viewer = NARROW[parent];
SELECT value
FROM
$User => d.level ← user;
$FileProperties => d.level ← fileProperties;
$OwnerProperties => d.level ← ownerProperties;
$Administrator => d.level ← administrator;
$STOP => {
d.stopFlag ← TRUE ;
RETURN;
};
ENDCASE => {
d.out.PutRope["\nNot Implemented\n"];
};
CreateButtons[d, parent]
END;
build an image from the data in parameter d
CreateButtons:
PUBLIC
ENTRY
PROC[d: MyData, parent: ViewerClasses.Viewer] = {
child: ViewerClasses.Viewer ← NIL;
EnquiryButton:
PROC[q: MBQueue.Queue, name: Rope.
ROPE, proc: Buttons.ButtonProc, width:
INTEGER ← d.maxW,
guarded:
BOOL ←
FALSE, doc:Rope.
ROPE ←
NIL] =
BEGIN
IF q #
NIL
THEN child ← q.CreateButton[
info: [name: name, parent: kids, border:
TRUE,
wy: child.wy, wx: child.wx + width - 1, ww: width],
proc: proc,
clientData: d,
fork: TRUE,
paint: FALSE,
guarded: guarded,
documentation: doc]
ELSE child ← Buttons.Create[
info: [name: name, parent: kids, border:
TRUE,
wy: child.wy, wx: child.wx + width - 1, ww: width],
proc: proc,
clientData: d,
fork: TRUE,
paint: FALSE,
guarded: guarded,
documentation: doc];
END;
LabelText:
PROC[q: MBQueue.Queue, name, data: Rope.
ROPE, prev: ViewerClasses.Viewer,
width: INTEGER ← d.maxW, textWidth: INTEGER ← 2*d.maxW, newline: BOOL ← TRUE,
textLabelProc: Buttons.ButtonProc ← OtherTextLabelProc]
RETURNS[ViewerClasses.Viewer] =
BEGIN
x: INTEGER = IF newline THEN 2 ELSE child.wx + width + (textWidth) - 1;
y: INTEGER = IF newline THEN child.wy + child.wh + 1 ELSE child.wy;
child ← ViewerTools.MakeNewTextViewer[
info: [parent: kids, wh: d.buttH, ww: width + (textWidth), scrollable:
FALSE,
data: IF prev = NIL THEN data ELSE ViewerTools.GetContents[prev],
border: FALSE,
wx: x + width + 2, wy: y],
paint: FALSE ];
[] ← q.CreateButton[
info: [name: name, parent: kids, wh: d.buttH,
border: FALSE, wx: x, wy: y],
proc: textLabelProc, clientData: child, fork: FALSE, paint: FALSE];
RETURN[child]
END;
Label:
PROC[name: Rope.
ROPE] = {
child ← Labels.Create[
info: [name: name, parent: kids, border:
FALSE,
wy: child.wy + child.wh + (IF child.class.flavor = $Button THEN -1 ELSE 2),
wx: 2],
paint: FALSE ];
};
Rule:
PROC = {
child ← Rules.Create[
info: [parent: kids, border:
FALSE,
wy: IF child = NIL THEN 0 ELSE child.wy + child.wh + 2, wx: 0, ww: kids.ww, wh: 1],
paint: FALSE ];
Containers.ChildXBound[kids, child];
};
userButtons:
PROC = {
Label["Command: "];
EnquiryButton[q: d.q, name: "List", proc: ListFilesProc];
EnquiryButton[q: d.q, name: "Delete", proc: DeleteFilesProc, guarded: FALSE];
EnquiryButton[q: d.q, name: "Copy", proc: CopyFilesProc];
EnquiryButton[q: d.q, name: "FullCopy", proc: FullCopyFilesProc];
EnquiryButton[q: d.q, name: "Options", proc: OptionsProc];
Label[""];
These buttons no longer needed
EnquiryButton[q: d.q, name: "ListInterim", proc: ListInterimProc];
EnquiryButton[q: d.q, name: "Convert", proc: ConvertDirectoryProc, guarded: TRUE, doc: "Convert requires confirmation"];
EnquiryButton[q: d.q, name: "Rename", proc: RenameProc];
IF d.displayOptions
THEN {
buttonCount: INTEGER ← 0 ;
count: INT;
option: AlpineEnvironment.Property;
propertyName: ROPE ;
Rule[];
Label["List options: "];
FOR count
IN [0..NumberOfAlpineProperties)
DO
[option, propertyName] ← PropertySetToRopeArray[count];
IF (buttonCount >= 4)
THEN {
Label[""];
buttonCount ← 0 ;
};
buttonCount ← buttonCount + 1 ;
EnquiryButton[q: NIL, name: propertyName, proc: ChangeOptionsProc, width: d.maxBW];
IF d.displayProperties[option]
THEN {
Buttons.SetDisplayStyle[child, $WhiteOnBlack];
};
ENDLOOP;
Label["Priority option:"];
EnquiryButton[q: NIL, name: "Background", proc: ChangePriorityProc, width: d.maxBW];
IF d.background THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack];
Label["Delete options:"];
EnquiryButton[q: NIL, name: "AutoDelete", proc: ChangeAutoDeleteProc, width: d.maxBW];
IF d.AutoDelete THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack];
propertyName ← Rope.Cat["Keep ", IO.PutFR["%g", IO.int[d.DelVerCount]], " versions"];
EnquiryButton[q: NIL, name: propertyName, proc: ChangeDelVerProc, width: d.maxBW];
};
};
filePropertiesButtons:
PROC = {
Label["Function: "];
EnquiryButton[q: d.q, name: "Examine", proc: ExamineProc];
EnquiryButton[q: d.q, name: "Apply", proc: ApplyProc, guarded:
TRUE,
doc: "Apply requires confirmation; single file application only"];
Rule[];
d.oStringName ← LabelText[
q: d.q,
name: "stringName:",
data: "",
prev: d.oStringName,
width: d.maxBW,
textWidth: 5*d.maxW];
d.oByteLength ← LabelText[
q: d.q,
name: "byteLength:",
data: "",
prev: d.oByteLength,
width: d.maxBW,
textWidth: d.maxW/2 ];
d.oSize ← LabelText[
q: d.q,
name: "size:",
data: "",
prev: d.oSize,
width: d.maxBW,
textWidth: d.maxW/2,
newline: FALSE ];
d.oFileKeep ← LabelText[
q: d.q,
name: "keep:",
data: "",
prev: d.oFileKeep,
width: d.maxBW,
textWidth: d.maxW/2,
newline: FALSE ];
d.oHighWaterMark ← LabelText[
q: d.q,
name: "highWaterMark:",
data: "",
prev: d.oHighWaterMark,
width: d.maxBW,
textWidth: d.maxW/2 ];
d.oOwner ← LabelText[
q: d.q,
name: "owner:",
data: "",
prev: d.oOwner,
width: d.maxBW,
textWidth: d.maxW/2,
newline: FALSE ];
d.oVersion ← LabelText[
q: d.q,
name: "version:",
data: "",
prev: d.oVersion,
width: d.maxBW,
textWidth: d.maxW/2,
newline: FALSE ];
d.oReadAccess ← LabelText[
q: d.q,
name: "readAccess:",
data: "",
prev: d.oReadAccess,
width: d.maxBW,
textWidth: 5*d.maxW];
d.oModifyAccess ← LabelText[
q: d.q,
name: "modifyAccess:",
data: "",
prev: d.oModifyAccess,
width: d.maxBW,
textWidth: 5*d.maxW];
};
ownerPropertiesButtons:
PROC = {
Label["Function: "];
EnquiryButton[q: d.q, name: "Quota", proc: QuotaProc];
EnquiryButton[q: d.q, name: "Get", proc: GetOwnerPropertiesProc];
EnquiryButton[q: d.q, name: "Put", proc: PutOwnerPropertiesProc, guarded:
TRUE,
doc: "Put owner properties requires confirmation"];
Rule[];
d.oOwnerKeep ← LabelText[
q: d.q,
name: "default Keep:",
data: "",
prev: d.oOwnerKeep,
width: 2*d.maxW,
d.oCreateAccessList ← LabelText[
q: d.q,
name: "createAccess:",
data: "",
prev: d.oCreateAccessList,
width: 2*d.maxW,
textWidth: 5*d.maxW];
d.oRootReadAccess ← LabelText[
q: d.q,
name: "root readAccess:",
data: "",
prev: d.oRootReadAccess,
width: 2*d.maxW,
textWidth: 5*d.maxW];
d.oRootModifyAccess ← LabelText[
q: d.q,
name: "root modifyAccess:",
data: "",
prev: d.oRootModifyAccess,
width: 2*d.maxW,
textWidth: 5*d.maxW];
};
administratorButtons:
PROC = {
Label["Command: "];
EnquiryButton[q: d.q, name: "CreateOwner", proc: CreateOwnerProc, width: d.maxBW, guarded: TRUE, doc: "Create requires confirmation"];
EnquiryButton[q: d.q, name: "DestroyOwner", proc: DestroyOwnerProc, width: d.maxBW, guarded: TRUE, doc: "Destroy requires confirmation"];
EnquiryButton[q: d.q, name: "WriteQuota", proc: WriteQuotaProc, width: d.maxBW, guarded: TRUE, doc: "Write Quota requires confirmation"];
EnquiryButton[q: d.q, name: "ListOwners", proc: ListOwnersProc, width: d.maxBW];
EnquiryButton[q: d.q, name: "ReadStatistics", proc: ReadDBPropertiesProc, width: d.maxBW];
Rule[];
d.oQuota ← LabelText[
q: d.q,
name: "quota:",
data: "",
prev: d.oQuota,
width: d.maxBW,
textWidth: 5*d.maxW];
Rule[];
Label["Option: "];
EnquiryButton[q: NIL, name: "Assert Wheel", proc: ChangeAssertWheel, width: d.maxBW];
IF d.assertWheel
THEN {
Buttons.SetDisplayStyle[child, $WhiteOnBlack];
};
EnquiryButton[q: NIL, name: "Break Locks", proc: ChangeBreakLocks, width: d.maxBW];
IF d.breakLocks
THEN {
Buttons.SetDisplayStyle[child, $WhiteOnBlack];
};
};
kids: ViewerClasses.Viewer = Containers.Create[ info: [parent: parent, border: FALSE, scrollable: FALSE, wx: 0, wy: -9999, ww: 9999, wh: 0] ];
start of body of CreateButtons
Containers.ChildXBound[parent, kids];
Rule[];
ask for source
d.src ← LabelText[
q: d.q,
name: "Source:",
data: NamePrefixes.first,
prev: d.src,
textWidth: 5*d.maxW,
textLabelProc: ServerTextLabelProc ];
ask for destination
d.dest ← LabelText[
q: d.q,
name: "Destination:",
data: NamePrefixes.first,
prev: d.dest,
textWidth: 5*d.maxW,
textLabelProc: ServerTextLabelProc ];
IF d.level = user
THEN {
userButtons[];
IF ~d.AutoDelete
THEN {
Rule[];
d.oDeleteConfirm ← LabelText[
q: d.q,
name: "OK to delete",
data: "",
prev: NIL,
width: d.maxBW,
textWidth: 5*d.maxW];
Label[""];
EnquiryButton[q: NIL, name: "", proc: YesProc, width: d.maxBW]; -- Yes
d.yesButton ← child;
EnquiryButton[q: NIL, name: "", proc: NoProc, width: d.maxBW]; -- No
d.noButton ← child;
};
}
ELSE d.oDeleteConfirm ← NIL;
IF d.level = fileProperties THEN filePropertiesButtons[]
ELSE {
d.oStringName ← d.oByteLength ← d.oHighWaterMark ← d.oSize ← d.oReadAccess ← d.oModifyAccess ← d.oOwner ← d.oFileKeep ← NIL;
} ;
IF d.level = ownerProperties
THEN ownerPropertiesButtons[]
ELSE {
d.oCreateAccessList ← NIL ;
d.oRootReadAccess ← NIL ;
d.oRootModifyAccess ← NIL ;
d.oOwnerKeep ← NIL ;
};
IF d.level = administrator
THEN administratorButtons[]
ELSE d.oQuota ←
NIL;
Rule[];
{
kidsY: INTEGER = d.topChild.wy + d.topChild.wh + 2;
kidsH: INTEGER = child.wy + child.wh + 2;
IF d.kids # NIL THEN ViewerOps.DestroyViewer[d.kids, FALSE];
d.kids ← kids;
ViewerOps.MoveViewer[viewer: d.script, x: 0, y: kidsY + kidsH, w: d.script.ww,
h: parent.ch - (kids.wy + kidsH),
paint: FALSE];
ViewerOps.SetOpenHeight[parent, kidsY + kidsH + 8 * d.buttH];
IF NOT parent.iconic THEN ViewerOps.ComputeColumn[parent.column];
ViewerOps.MoveViewer[viewer: kids, x: kids.wx, y: kidsY, w: kids.ww, h: kidsH];
};
};
ServerTextLabelProc: Buttons.ButtonProc = {
parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
text: ViewerClasses.Viewer = NARROW[clientData];
selection: REF ViewerTools.SelPosRec ← NIL;
SELECT mouseButton
FROM
red => {
IF ViewerTools.GetSelectedViewer[] = text
THEN {
NextName:
PROC [this:
ROPE, list:
LIST
OF
ROPE]
RETURNS [next:
ROPE ←
NIL] = {
IF list = NIL THEN RETURN;
FOR l:
LIST
OF
ROPE ← list, l.rest
UNTIL l =
NIL
DO
IF this.Equal[l.first,
FALSE]
THEN
RETURN[
IF l.rest =
NIL
THEN list.first
ELSE
l.rest.first]
ENDLOOP;
RETURN[list.first]
};
contents: ROPE ← ViewerTools.GetContents[text];
ViewerTools.SetContents[text, contents ← NextName[contents,
NamePrefixes]];
selection ← NEW[ViewerTools.SelPosRec ← [start: contents.Length[], length: 0]];
};
ViewerTools.SetSelection[text, selection];
};
blue => { ViewerTools.SetContents[text, NIL]; ViewerTools.SetSelection[text, NIL] };
yellow => NULL;
ENDCASE => ERROR;
};
OtherTextLabelProc: Buttons.ButtonProc = {
parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
text: ViewerClasses.Viewer = NARROW[clientData];
SELECT mouseButton
FROM
red => ViewerTools.SetSelection[text, NIL];
blue => { ViewerTools.SetContents[text, NIL]; ViewerTools.SetSelection[text, NIL] };
yellow => NULL;
ENDCASE => ERROR;
};
Selector:
TYPE =
REF SelectorRec;
SelectorRec:
TYPE =
RECORD[
value: REF ATOM,
change: PROC[parent: ViewerClasses.Viewer, clientData: REF ANY, value: ATOM],
clientData: REF ANY,
buttons: LIST OF Buttons.Button,
values: LIST OF ATOM ];
CreateSelector: PROC[ name: Rope.ROPE, values: LIST OF ATOM, init: REF ATOM ← NIL, change: PROC[parent: ViewerClasses.Viewer, clientData: REF ANY, value: ATOM] ← NIL, clientData: MyData, viewer: ViewerClasses.Viewer, x, y: INTEGER]
RETURNS[child: ViewerClasses.Viewer, value:
REF
ATOM] = {
selector: Selector ←
NEW[ SelectorRec ←
[value:
IF init #
NIL
THEN init
ELSE
NEW[
ATOM←values.first],
change: change,
clientData: clientData,
buttons: NIL,
values: values ] ];
last: LIST OF Buttons.Button ← NIL;
value ← selector.value;
child ← Labels.Create[info: [name: name, parent: viewer, border: FALSE, wx: x, wy: y] ];
FOR a: LIST OF ATOM ← values, a.rest UNTIL a = NIL
DO
IF a.first = $STOP
THEN child ← Buttons.Create[
info: [name: Atom.GetPName[a.first], parent: viewer, border: TRUE,
wy: child.wy, wx: child.wx + child.ww + 2],
proc: SelectorProc,
clientData: selector,
fork: TRUE,
paint: TRUE]
ELSE child ← clientData.q.CreateButton[
info: [name: Atom.GetPName[a.first], parent: viewer, border:
TRUE,
wy: child.wy, wx: child.wx + child.ww + 2],
proc: SelectorProc,
clientData: selector,
fork: TRUE,
paint: TRUE];
IF last = NIL
THEN last ← selector.buttons ← CONS[first: child, rest: NIL]
ELSE { last.rest ← CONS[first: child, rest: NIL]; last ← last.rest };
IF a.first = selector.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack];
ENDLOOP;
};
SelectorProc: Buttons.ButtonProc = {
parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
self: Buttons.Button = NARROW[parent];
selector: Selector = NARROW[clientData];
buttons: LIST OF Buttons.Button ← selector.buttons;
changeHighlight: BOOL = NOT Rope.Equal[self.name,"STOP"];
FOR a: LIST OF ATOM ← selector.values, a.rest UNTIL a = NIL
DO
IF self = buttons.first
THEN
BEGIN
selector.value^ ← a.first;
IF selector.change # NIL THEN selector.change[self.parent, selector.clientData, a.first];
IF changeHighlight THEN Buttons.SetDisplayStyle[buttons.first, $WhiteOnBlack];
END
ELSE IF changeHighlight THEN Buttons.SetDisplayStyle[buttons.first, $BlackOnWhite];
buttons ← buttons.rest;
ENDLOOP;
};
ReactToProfile: UserProfile.ProfileChangedProc = {
NamePrefixes ← UserProfile.ListOfTokens[
key: "Yodel.NamePrefixes",
default: defaultNamePrefixes
];
};
Commander.Register[key: "Yodel", proc: Create,
doc: "Performs Chat-like functions for Alpine File Servers"];
ReactToProfile[firstTime];
UserProfile.CallWhenProfileChanges[ReactToProfile];
Bob Hagmann June 10, 1985 4:56:41 pm PDT
reformatted
Bob Hagmann June 12, 1985 9:06:03 am PDT
added Rename, and delete options
Bob Hagmann July 9, 1985 9:11:34 am PDT
changes to: CreateButtons