WalnutMsgSetButtonsImpl.mesa
Copyright Ó 1985, 1988, 1992 by Xerox Corporation. All rights reserved.
Willie-Sue, July 5, 1990 1:00:44 pm PDT
Pavel, February 7, 1986 11:43:05 am PST
Jack Kent April 7, 1987 5:14:42 pm PST
Doug Terry, October 16, 1990 9:29 am PDT
Swinehart, June 19, 1991 8:16 am PDT
Contents: co-ordinates MsgSet button handling for WalnutControlWindow
Willie-s, April 27, 1992 7:52 pm PDT
created October, 1982 by Willie-Sue
Last edit by:
Willie-Sue on: January 3, 1985 4:49:23 pm PST
Donahue on: January 31, 1985 3:13:33 pm PST
(To be consistent with new WalnutDisplayerOps, WalnutDisplayerOpsInternal)
(Restart code calls proc to redisplay all message set viewers, since check for version is done there)
(Again, this got much smaller and simpler through changes to WalnutWindow, WalnutWindowInternal)
DIRECTORY
Containers USING [ChildXBound],
EditSpan USING [ChangeLooks, noLooks, Replace],
FileNames USING [StripVersionNumber],
FS USING [Error, FileInfo],
PFS,
Rope,
RopeList USING [DRemove, Length],
TBQueue USING [ AppendToTiogaButton, CreateTiogaButtonFromNode ],
TEditDocument USING [TEditDocumentData],
TextLooks USING [RopeToLooks],
TextNode USING [LastWithin, NodeItself, Span],
Tioga USING [Node],
TiogaButtons USING [ AppendToButton, ChangeButtonLooks, CreateViewer, DeleteButton, GetRope, LoadViewer, MarkViewerNotEdited, RegisterModifiedProc, SetState, TiogaButton, TiogaButtonProc, WasModifiedProc ],
TiogaIO USING [FromRope, ToFile],
TiogaOps USING [GetRope, InsertRope, IsComment, Ref, StepForward],
UserProfile USING [Number, Token],
VFonts USING [StringWidth],
ViewerOps USING [ AddProp, ComputeColumn, DestroyViewer, FetchProp, GrowViewer, MoveViewer, OpenIcon, PaintViewer, SetOpenHeight ],
ViewerClasses USING [Viewer],
ViewerSpecs USING [openLeftWidth, openRightWidth, scrollBarW],
WalnutOps,
WalnutInternal USING [alternateWalnutIcons, ComeFrom, displayMsgSetInIcon, labelledWalnutIcons, QDisplayMsgSet, unLabelledWalnutIcons],
WalnutWindow USING [],
WalnutWindowSidedoor,
WalnutWindowPrivate
USING[MsgSetButton, MsgSetButtonObject, MsgSetInfo, WalnutHandle, WalnutHandleRec];
WalnutMsgSetButtonsImpl:
CEDAR
PROGRAM
IMPORTS
FileNames, FS, PFS, Rope, RopeList, UserProfile,
Containers, EditSpan, TBQueue, TextNode, TextLooks, TiogaButtons, TiogaIO, TiogaOps, VFonts, ViewerOps, ViewerSpecs,
WalnutOps, WalnutInternal
EXPORTS WalnutWindow, WalnutInternal, WalnutWindowSidedoor =
BEGIN OPEN WalnutInternal;
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
TiogaButton: TYPE = TiogaButtons.TiogaButton;
MsgSet: TYPE = WalnutOps.MsgSet;
WalnutHandle: TYPE = WalnutWindowPrivate.WalnutHandle;
WalnutHandleRec: PUBLIC TYPE = WalnutWindowPrivate.WalnutHandleRec;
MsgSetButton: TYPE = WalnutWindowPrivate.MsgSetButton;
MsgSetButtonObject: TYPE = WalnutWindowPrivate.MsgSetButtonObject;
MsgSetInfo: TYPE = WalnutWindowPrivate.MsgSetInfo;
msbDefaultLooks:
PUBLIC
ROPE ¬
UserProfile.Token[key: "Walnut.MsgSetButtonDefaultLooks", default: ""];
msbSelectedLooks:
PUBLIC ROPE ¬
UserProfile.Token[key: "Walnut.MsgSetButtonSelectedLooks", default: "bi"];
lineHeight: INTEGER = 12; -- different for TiogaButtons
maxLines: INT ¬ 10;
spaceWidth: INT ¬ VFonts.StringWidth["P"];
nonExistentMsgSetLooks: ROPE ¬
UserProfile.Token[key: "Walnut.NonExistentMsgSetLooks", default: "y"];
Invariant:
IF displayMsgSetInIcon AND selectedMsgSetButtons # NIL THEN
Current icon is labelled and the label = selectedMsgSetButtons.msgSet.name
ELSE
Current icon is unlabelled
The invariant is established at the beginning by initialising as follows:
walnutIcon ← unLabelledWalnutIcon
newMailIcon ← unLabelledNewMailIcon
walnut.icon ← walnutIcon
selectedMsgSetButtons ← NIL
The maintenance of the invariant is split between this procedure and DeselectMsgSet, below.
SelectMsgSetProc: TiogaButtons.TiogaButtonProc = {
IF red & cntl & shift THEN msgs in selected msgsets ComeFrom those msgsets to this msgSet
IF red THEN deselect all & select this one; IF yellow then display;
IF blue THEN toggle whether selected or not
msbH: MsgSetButton = NARROW[clientData];
msb, msb2: MsgSetButton;
wH: WalnutHandle;
IF msbH = NIL THEN RETURN; -- no MsgSetButton for this tioga button
wH ¬ msbH.wH;
IF (mouseButton = red)
AND shift
THEN {
IF control
THEN WalnutInternal.ComeFrom[msbH]
ELSE TiogaOps.InsertRope[msbH.msgSet.name];
RETURN;
};
IF mouseButton = yellow
THEN {
MSDisplay[msbH, shift];
RETURN;
};
IF mouseButton = red
THEN {
-- deselect any selected
IF (msb ¬ wH.selectedMsgSetButtons) #
NIL
THEN {
wH.selectedMsgSetButtons ¬ NIL;
DO
FOR tbL:
LIST
OF TiogaButton ¬ msb.allButtons, tbL.rest
UNTIL tbL =
NIL
DO
TiogaButtons.ChangeButtonLooks[
button: tbL.first,
addLooks: msbDefaultLooks,
removeLooks: msbSelectedLooks
];
ENDLOOP;
IF (msb2 ¬ msb.selected) =
NIL
THEN
EXIT;
msb.selected ¬ NIL;
msb ¬ msb2;
ENDLOOP;
}
}
ELSE {
-- blue button, toggle the state of this msgSet
FOR msb ¬ wH.selectedMsgSetButtons, msb.selected
UNTIL msb=
NIL
DO
IF msb = msbH
THEN {
-- This one was already selected; deselect it and quit
DeselectMsgSet[msbH];
RETURN;
};
ENDLOOP;
msbH.selected ¬ wH.selectedMsgSetButtons;
};
Here we actually select the tioga buttons for the clicked button
wH.selectedMsgSetButtons ¬ msbH;
FOR tbL:
LIST
OF TiogaButton ¬ msbH.allButtons, tbL.rest
UNTIL tbL =
NIL
DO
TiogaButtons.ChangeButtonLooks[
button: tbL.first,
addLooks: msbSelectedLooks,
removeLooks: msbDefaultLooks
];
ENDLOOP;
Fix up the icon, if necessary
FixIconAndLabel[wH];
};
FixIconAndLabel:
PROC[wH: WalnutHandle] = {
-- This procedure does not repaint the icon, since most callers won't want that
IF displayMsgSetInIcon
AND wH.selectedMsgSetButtons #
NIL
THEN {
label: ROPE ¬ Rope.Concat[wH.identifierPrefix, wH.selectedMsgSetButtons.msgSet.name];
FOR msb: MsgSetButton ¬ wH.selectedMsgSetButtons.selected, msb.selected
UNTIL msb =
NIL
DO
label ¬ Rope.Cat[label, ", ", msb.msgSet.name];
ENDLOOP;
wH.walnut.label ¬ label;
wH.iconSet ¬ labelledWalnutIcons;
}
ELSE
IF (wH.walnut.label ¬ wH.iconIdentifier) =
NIL
THEN
wH.iconSet ¬ unLabelledWalnutIcons ELSE wH.iconSet ¬ alternateWalnutIcons;
wH.walnut.icon ¬ wH.iconSet[wH.whichIcon];
};
ShowMsgSetButtons:
PUBLIC
PROC[wH: WalnutHandle] = {
msL: LIST OF ROPE;
first: BOOL ¬ TRUE;
visibleSpace: INT;
version, numMsgSets: INT;
The following code is commented out since having a local and remote MsgSetButtonsFile is not required. Plus, the "sneaky" trick doesn't work. ... DBT
remoteName: ROPE = wH.localMsgSetButtonsFile.Substr[2]; -- sneaky
What DOES work is for local and remote files to be one and the same! DCS February 26, 1991
End of commented out code. ...DBT
remoteName: ROPE = wH.localMsgSetButtonsFile;
wH.msgSetButtonsFile ¬ FS.FileInfo[remoteName !
FS.Error => IF error.code = $unknownFile THEN CONTINUE ].fullFName;
IF wH.msgSetButtonsFile # NIL THEN wH.msgSetButtonsFile ¬ FileNames.StripVersionNumber[wH.msgSetButtonsFile];
[version, numMsgSets] ¬ WalnutOps.MsgSetsInfo[wH.opsH];
IF wH.firstMsgSetButton #
NIL
THEN
IF version = wH.msgSetsVersion
THEN {
-- check for changed, displayed msgSets
FOR msb: MsgSetButton ¬ wH.firstMsgSetButton, msb.next
UNTIL msb=
NIL
DO
IF msb.msViewer #
NIL
THEN {
IF msb.msViewer.destroyed
THEN {
msb.msViewer ¬ NIL;
msb.msgSet.version ¬ -1;
}
ELSE [] ¬ WalnutInternal.QDisplayMsgSet[wH, msb]
}
ELSE msb.msgSet.version ¬ -1; -- might have been displayed once
ENDLOOP;
RETURN;
};
[msL, wH.msgSetsVersion] ¬ WalnutOps.MsgSetNames[opsHandle: wH.opsH, alphaOrder: TRUE];
IF RopeList.Length[msL] = 2
THEN
msL ¬ LIST[WalnutOps.ActiveName, WalnutOps.DeletedName]
ELSE {
-- more than just active & deleted
change the list so active and deleted are first
msL ¬ RopeList.DRemove[msL, WalnutOps.ActiveName, FALSE];
msL ¬ RopeList.DRemove[msL, WalnutOps.DeletedName, FALSE];
msL ¬ CONS[WalnutOps.ActiveName, CONS[WalnutOps.DeletedName, msL]];
};
calculate how big the area for msgSet buttons should be
BEGIN
numLines: INT ¬ UserProfile.Number["Walnut.NumMsgSetButtonsLines", -1];
IF numLines = -1
THEN {
colWidth:
INT ¬ (
IF wH.walnut.column = right
THEN ViewerSpecs.openRightWidth
ELSE ViewerSpecs.openLeftWidth) - ViewerSpecs.scrollBarW;
numChars, totalCharWidth: INT ¬ 0;
FOR nL:
LIST
OF
ROPE ¬ msL, nL.rest
UNTIL nL=
NIL
DO
numChars ¬ numChars + nL.first.Length[] + 2; -- two spaces between
ENDLOOP;
totalCharWidth ¬ numChars*spaceWidth;
numLines ¬ MAX[4, (totalCharWidth/colWidth) + 1];
IF numLines <= 0
THEN numLines ¬ 1
ELSE IF numLines > maxLines THEN numLines ¬ maxLines;
};
visibleSpace ¬ numLines * lineHeight + 1;
END;
IF wH.msgSetsTViewer # NIL THEN DestroyAllMsgSetButtons[wH]; -- start from scratch; it's easier
wH.msgSetsTViewer ¬ TiogaButtons.CreateViewer[
info: [wy: wH.walnutRulerBefore.wy + wH.walnutRulerBefore.wh, ww: wH.walnut.ww,
wh: visibleSpace, parent: wH.walnut, border: FALSE] ];
Containers.ChildXBound[wH.walnut, wH.msgSetsTViewer];
BEGIN
allMsgSetsNode: Tioga.Node;
allMsgSets: ROPE ¬ msL.first;
allSpan: TextNode.Span;
FOR mL:
LIST
OF
ROPE ¬ msL.rest, mL.rest
UNTIL mL=
NIL
DO
allMsgSets ¬ Rope.Cat[allMsgSets, " ", mL.first];
ENDLOOP;
allMsgSetsNode ¬ TiogaIO.FromRope[allMsgSets];
allSpan.start ¬ [TextNode.LastWithin[allMsgSetsNode], TextNode.NodeItself];
allSpan.end ¬ allSpan.start;
EditSpan.ChangeLooks[ allMsgSetsNode, allSpan, EditSpan.noLooks, TextLooks.RopeToLooks[msbDefaultLooks] ];
IF wH.msgSetButtonsFile #
NIL
THEN {
root: Tioga.Node;
lastChild: Tioga.Node;
TiogaButtons.LoadViewer[viewer: wH.msgSetsTViewer, fileName: wH.msgSetButtonsFile];
find and replace last node with allMsgSetsNode - such fun. Assumes at least two nodes
TiogaButtons.SetState[wH.msgSetsTViewer, editing];
root ¬ NARROW[wH.msgSetsTViewer.data, TEditDocument.TEditDocumentData].text;
lastChild ¬ TextNode.LastWithin[root];
[] ¬ EditSpan.Replace[destRoot: root, sourceRoot: allMsgSetsNode,
dest: [[lastChild, TextNode.NodeItself], [lastChild, TextNode.NodeItself]],
source: allSpan,
saveForPaste:
FALSE
];
TiogaButtons.MarkViewerNotEdited[root];
TiogaButtons.SetState[wH.msgSetsTViewer, buttoning];
}
ELSE {
-- generate a local file with all the msg sets in it
[] ¬ TiogaIO.ToFile[fileName: PFS.PathFromRope[wH.localMsgSetButtonsFile], root: allMsgSetsNode];
TiogaButtons.LoadViewer[viewer: wH.msgSetsTViewer, fileName: wH.localMsgSetButtonsFile];
};
END;
ViewerOps.AddProp[wH.msgSetsTViewer, $WalnutHandle, wH];
TiogaButtons.RegisterModifiedProc[v: wH.msgSetsTViewer, proc: BuildMsgSetButtons];
BEGIN
newY: INTEGER ¬ wH.walnutRulerBefore.wy + wH.walnutRulerBefore.wh + visibleSpace;
v: Viewer = CheckOptions[];
CheckOptions:
PROC
RETURNS[v: Viewer] = {
IF wH.oldMailReader #
NIL
THEN
IF
NOT (v ¬ wH.oldMailReader.container).destroyed
THEN
RETURN[v]
ELSE { wH.oldMailReader ¬ NIL; RETURN[NIL]};
IF wH.printingOptions #
NIL
THEN
IF
NOT (v ¬ wH.printingOptions.container).destroyed
THEN
RETURN[v]
ELSE { wH.printingOptions ¬ NIL; RETURN[NIL]};
};
IF wH.walnutRulerAfter.wy # newY
THEN {
ViewerOps.MoveViewer[wH.walnutRulerAfter, wH.walnutRulerAfter.wx,
newY, wH.walnutRulerAfter.ww, wH.walnutRulerAfter.wh, FALSE];
newY ¬ wH.walnutRulerAfter.wy+wH.walnutRulerAfter.wh+1;
IF v #
NIL AND NOT v.destroyed
THEN {
ViewerOps.MoveViewer[v, v.wx, newY, v.ww, v.wh, FALSE];
newY ¬ v.wy+v.wh+1;
};
ViewerOps.MoveViewer[wH.walnutTS, wH.walnutTS.wx,
newY, wH.walnutTS.ww, wH.walnutTS.wh, FALSE];
ViewerOps.SetOpenHeight[wH.msgSetsTViewer, visibleSpace];
ViewerOps.ComputeColumn[wH.walnut.column];
ViewerOps.PaintViewer[wH.walnutRulerAfter, all];
};
END;
DoBuildMsgSetButtons[wH, msL];
msb ← wH.activeMsgSetButton ← AddMSButton[wH, msb, WalnutOps.ActiveName, FALSE];
msb ← wH.deletedMsgSetButton← AddMSButton[wH, msb, WalnutOps.DeletedName];
FOR msL2: LIST OF ROPE ← msL, msL2.rest UNTIL msL2 = NIL DO
IF ~Rope.Equal[(ms ← msL2.first), WalnutOps.ActiveName, FALSE] AND
~Rope.Equal[ms, WalnutOps.DeletedName, FALSE] THEN
msb ← AddMSButton[wH, msb, ms];
ENDLOOP;
};
GetSelectedMsgSets:
PUBLIC
PROC[wH: WalnutHandle]
RETURNS[msL: LIST OF MsgSetButton] = {
FOR msB: MsgSetButton ¬ wH.selectedMsgSetButtons, msB.selected
UNTIL msB=
NIL
DO
msL ¬ CONS[msB, msL];
ENDLOOP;
};
GetSelectedMsgSetNames:
PUBLIC
PROC[wH: WalnutHandle]
RETURNS[msgSetNames: LIST OF ROPE] = {
FOR msB: MsgSetButton ¬ wH.selectedMsgSetButtons, msB.selected
UNTIL msB=
NIL
DO
msgSetNames ¬ CONS[msB.msgSet.name, msgSetNames];
ENDLOOP;
};
AddMsgSetButton:
PUBLIC
PROC[wH: WalnutHandle, msgSet: Rope.
ROPE, select:
BOOL] = {
thisMsb: MsgSetButton;
prevMsb: MsgSetButton ¬ wH.deletedMsgSetButton;
DO
nextMsb: MsgSetButton ¬ prevMsb.next;
IF nextMsb =
NIL
THEN
{ thisMsb ¬ AddMSButton[wH, prevMsb, msgSet]; EXIT };
IF Rope.Compare[msgSet, nextMsb.msgSet.name] = less
THEN
{ thisMsb ¬ AddMSButton[wH, prevMsb, msgSet]; EXIT };
prevMsb ¬ nextMsb;
ENDLOOP;
IF select THEN SelectMsgSetProc[button: NIL, clientData: thisMsb]; -- red-select new MsgSet
};
DeleteMsgSetButton:
PUBLIC
PROC[wH: WalnutHandle, msgSet:
ROPE] = {
if msgSet is Active, just destroy viewer, but not button
prevMsb: MsgSetButton ¬ wH.firstMsgSetButton;
FOR msb: MsgSetButton ¬ wH.firstMsgSetButton, msb.next UNTIL msb = NIL DO
IF Rope.Equal[msb.msgSet.name, msgSet,
FALSE]
THEN
{ msV: Viewer ¬ msb.msViewer;
IF msV # NIL AND ~msV.destroyed THEN ViewerOps.DestroyViewer[msV];
IF Rope.Equal[msgSet, WalnutOps.ActiveName]
THEN
{ msb.msViewer ¬ NIL; RETURN};
DeselectMsgSet[msb];
prevMsb.next ¬ msb.next;
TiogaButtons.DeleteButton[msb.mainButton];
FOR tbL:
LIST
OF TiogaButton ¬ msb.allButtons, tbL.rest
UNTIL tbL =
NIL
DO
IF tbL.first = msb.mainButton THEN LOOP;
TiogaButtons.ChangeButtonLooks[button: tbL.first, addLooks: nonExistentMsgSetLooks];
ENDLOOP;
RETURN
};
prevMsb ¬ msb;
ENDLOOP;
};
DestroyAllMsgSetButtons:
PUBLIC
PROC[wH: WalnutHandle] = {
wH.selectedMsgSetButtons ¬ NIL;
FOR msb: MsgSetButton ¬ wH.firstMsgSetButton, msb.next
UNTIL msb=
NIL
DO
IF msb.msViewer # NIL THEN ViewerOps.DestroyViewer[msb.msViewer];
msb.msViewer ¬ NIL;
ENDLOOP;
wH.firstMsgSetButton ¬ NIL;
ViewerOps.MoveViewer[wH.walnutRulerAfter, wH.walnutRulerAfter.wx,
wH.walnutRulerBefore.wy+wH.walnutRulerBefore.wh+14+2, wH.walnutRulerAfter.ww,
wH.walnutRulerAfter.wh, FALSE];
ViewerOps.MoveViewer[wH.walnutTS, wH.walnutTS.wx,
wH.walnutRulerAfter.wy+wH.walnutRulerAfter.wh+1, wH.walnutTS.ww,
wH.walnutTS.wh, FALSE];
ViewerOps.DestroyViewer[wH.msgSetsTViewer, FALSE];
wH.msgSetsTViewer ¬ NIL;
ViewerOps.ComputeColumn[wH.walnut.column];
ViewerOps.PaintViewer[wH.walnut, client];
};
SelectMsgSetsFromMSNames:
PUBLIC
PROC [wH: WalnutHandle, msNames:
LIST
OF
ROPE]
RETURNS[notFound: LIST OF ROPE] = {
Selects the message set buttons in the Walnut Control viewer which corresponds to the list of msNames given.
first: BOOLEAN ¬ TRUE;
IF wH.walnut = NIL THEN RETURN[msNames];
FOR msNameList:
LIST
OF
ROPE ¬ msNames, msNameList.rest
UNTIL msNameList =
NIL
DO
msb: MsgSetButton ¬ GetButton[wH, msNameList.first];
IF msb =
NIL
THEN {
notFound ¬ CONS[msNameList.first, notFound];
LOOP
};
SelectMsgSetProc[
button: NIL,
mouseButton: IF first THEN red ELSE blue,
clientData: msb];
first ¬ FALSE;
ENDLOOP;
IF displayMsgSetInIcon AND wH.walnut.iconic THEN ViewerOps.PaintViewer[wH.walnut, all];
};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AddMSButton:
PROC[wH: WalnutHandle, prevMsb: MsgSetButton, msgSet:
ROPE]
RETURNS[msbH: MsgSetButton] = {
assumes msgSet does not already have a button; adds it after prevMsb
spaceBt, newBt: TiogaButtons.TiogaButton;
prevBtL: LIST OF TiogaButton;
msbH ¬ NEW[MsgSetButtonObject ¬ [wH: wH, msgSet: [name: msgSet], next: prevMsb.next] ];
spaceBt ¬ TiogaButtons.AppendToButton[
button: prevMsb.mainButton, rope: " ", looks: msbDefaultLooks];
newBt ¬ TBQueue.AppendToTiogaButton[
q: wH.walnutQueue, button: spaceBt, rope: msgSet,
looks: msbDefaultLooks, proc: SelectMsgSetProc, clientData: msbH];
msbH.spaceButton ¬ spaceBt;
msbH.mainButton ¬ newBt;
msbH.allButtons ¬ LIST[newBt];
prevMsb.next ¬ msbH;
FOR tbL:
LIST
OF TiogaButton ¬ wH.orphanButtons, tbL.rest
UNTIL tbL =
NIL
DO
bt: TiogaButton;
IF NOT msgSet.Equal[TiogaButtons.GetRope[tbL.first], FALSE] THEN
{ prevBtL ¬ tbL; LOOP };
take this one off the orphan list
bt ¬ tbL.first;
IF prevBtL =
NIL
THEN wH.orphanButtons ¬ tbL.rest
ELSE prevBtL.rest ¬ tbL.rest;
msbH.allButtons ¬ CONS[bt, msbH.allButtons];
TiogaButtons.ChangeButtonLooks[button: bt, removeLooks: nonExistentMsgSetLooks];
prevBtL ¬ tbL;
ENDLOOP;
};
DeselectMsgSet:
PROC[msbH: MsgSetButton] = {
wH: WalnutHandle = msbH.wH;
msb: MsgSetButton ¬ wH.selectedMsgSetButtons;
FOR msb2: MsgSetButton ¬ msb, msb2.selected
UNTIL msb2=
NIL
DO
IF msb2 = msbH
THEN {
-- found on list so take off
msb.selected ¬ msb2.selected;
IF msbH = wH.selectedMsgSetButtons
THEN
wH.selectedMsgSetButtons ¬ msbH.selected;
msbH.selected ¬ NIL;
FOR tbL:
LIST
OF TiogaButton ¬ msb2.allButtons, tbL.rest
UNTIL tbL =
NIL
DO
TiogaButtons.ChangeButtonLooks[
button: tbL.first,
addLooks: msbDefaultLooks,
removeLooks: msbSelectedLooks
];
ENDLOOP;
Fix up the icon, if necessary
FixIconAndLabel[wH];
RETURN
};
msb ¬ msb2;
ENDLOOP;
};
MSDisplay:
PROC[msb: MsgSetButton, shift:
BOOL] = {
msV: Viewer = msb.msViewer;
IF (msV #
NIL)
AND ~msV.destroyed
THEN
{
IF msV.iconic
THEN ViewerOps.OpenIcon[msV, shift]
ELSE
IF shift
THEN ViewerOps.GrowViewer[msV]
ELSE ViewerOps.PaintViewer[msV, all] }
ELSE [] ¬ QDisplayMsgSet[msb.wH, msb, msV, shift];
};
GetButton:
PUBLIC
PROC[wH: WalnutHandle, msgSet:
ROPE]
RETURNS[MsgSetButton] = {
FOR msb: MsgSetButton ¬ wH.firstMsgSetButton, msb.next UNTIL msb = NIL DO
IF Rope.Equal[msb.msgSet.name, msgSet,
FALSE]
THEN
RETURN[msb];
ENDLOOP;
RETURN[NIL];
};
PrepareToEditMsgSetButtons:
PUBLIC
PROC[wH: WalnutHandle] = {
FOR msb: MsgSetButton ¬ wH.selectedMsgSetButtons, msb.next
UNTIL msb =
NIL
DO
FOR tb:
LIST
OF TiogaButton ¬ msb.allButtons, tb.rest
UNTIL tb =
NIL
DO
TiogaButtons.ChangeButtonLooks[button: tb.first, removeLooks: msbSelectedLooks];
ENDLOOP;
ENDLOOP;
FOR tbL:
LIST
OF TiogaButton ¬ wH.orphanButtons, tbL.rest
UNTIL tbL =
NIL
DO
TiogaButtons.ChangeButtonLooks[button: tbL.first, removeLooks: nonExistentMsgSetLooks];
ENDLOOP;
TiogaButtons.SetState[wH.msgSetsTViewer, editing];
};
whitespace:
ROPE = " \t\n\r\l";
BuildMsgSetButtons: TiogaButtons.WasModifiedProc ~ {
PROC [v: ViewerClasses.Viewer]
wH: WalnutHandle = NARROW[ViewerOps.FetchProp[v, $WalnutHandle]];
DoBuildMsgSetButtons[wH, WalnutOps.MsgSetNames[wH.opsH].mL ];
};
DoBuildMsgSetButtons:
PROC[wH: WalnutHandle, msList:
LIST
OF
ROPE] = {
root: Tioga.Node = NARROW[wH.msgSetsTViewer.data, TEditDocument.TEditDocumentData].text;
rope, name: ROPE;
start, end: INT;
length: INT;
prevMsb: MsgSetButton ¬ NIL;
msbH: MsgSetButton;
wH.orphanButtons ¬ NIL;
wH.firstMsgSetButton ¬ NIL;
create the MsgSetButtons from the list of msgSets
FOR mL:
LIST
OF
ROPE ¬ msList, mL.rest
UNTIL mL =
NIL
DO
name: ROPE = mL.first;
msb: MsgSetButton = NEW[MsgSetButtonObject ¬ [wH: wH, msgSet: [name: name]] ];
IF prevMsb #
NIL
THEN prevMsb.next ¬ msb
ELSE wH.firstMsgSetButton ¬ msb;
prevMsb ¬ msb;
SELECT
TRUE
FROM
Rope.Equal[name, WalnutOps.ActiveName, FALSE] => wH.activeMsgSetButton ¬ msb;
Rope.Equal[name, WalnutOps.DeletedName, FALSE] => wH.deletedMsgSetButton ¬ msb;
ENDCASE => NULL;
ENDLOOP;
FOR vL:
LIST
OF Viewer ¬ wH.msgSetViewerList, vL.rest
UNTIL vL =
NIL
DO
msI: MsgSetInfo;
name: ROPE;
msb: MsgSetButton;
IF vL.first.destroyed THEN LOOP;
msI ¬ NARROW[ViewerOps.FetchProp[vL.first, $MsgSetInfo]];
name ¬ msI.button.msgSet.name;
msb ¬ GetButton[wH, name];
msb.msViewer ¬ vL.first;
msI.button ¬ msb;
ENDLOOP;
FOR node: TiogaOps.Ref ¬ TiogaOps.StepForward[root], TiogaOps.StepForward[node]
UNTIL node=
NIL
DO
for each non-comment node, find text strings and turn them into buttons.
IF TiogaOps.IsComment[node] THEN LOOP;
rope ¬ TiogaOps.GetRope[node];
length ¬ Rope.Length[rope];
start ¬ Rope.SkipOver[rope, 0, whitespace];
WHILE start < length
DO
tb: TiogaButton;
end ¬ Rope.SkipTo[rope, start+1, whitespace];
name ¬ Rope.Substr[rope, start, end-start];
msbH ¬ GetButton[wH, name];
tb ¬ TBQueue.CreateTiogaButtonFromNode[q: wH.walnutQueue, node: node, start: start, end: end, proc: SelectMsgSetProc, clientData: msbH];
IF msbH #
NIL
THEN {
msbH.allButtons ¬ CONS[tb, msbH.allButtons];
msbH.mainButton ¬ tb; -- always the last one
}
ELSE {
TiogaButtons.ChangeButtonLooks[button: tb, addLooks: nonExistentMsgSetLooks];
wH.orphanButtons ¬ CONS[tb, wH.orphanButtons];
};
start ¬ Rope.SkipOver[rope, end, whitespace];
ENDLOOP;
ENDLOOP;
};
MakeMSButton:
PROC[wH: WalnutHandle, prevMsb: MsgSetButton, msgSet:
ROPE, node: TiogaOps.Ref, start:
INT ¬ 0, end:
INT ¬
INT.
LAST]
RETURNS[msbH: MsgSetButton] = {
assumes msgSet does not already have a button; adds it after prevMsb
newBt: TiogaButtons.TiogaButton;
msbH ¬ NEW[MsgSetButtonObject ¬ [wH: wH, msgSet: [name: msgSet], next: prevMsb.next] ];
newBt ¬ TBQueue.CreateTiogaButtonFromNode[q: wH.walnutQueue, node: node, start: start, end: end, proc: SelectMsgSetProc, clientData: msbH];
msbH.mainButton ¬ newBt;
msbH.allButtons ¬ LIST[newBt];
prevMsb.next ¬ msbH;
};
END.