DFToolUtilitiesImpl.mesa
last edited by Levin on December 6, 1983 2:32 pm
DIRECTORY
Buttons USING [Button, ButtonProc, Create],
DFToolInternal USING [
Choice, DFTool, OpDefiner, Operation, OpTable, OptionSelector, Parameters, ToolParameters, UserClass],
FS USING [ComponentPositions, Error, ExpandName],
IO USING [Close, EndOfStream, GetTokenRope, IDProc, RIS, STREAM],
Labels USING [Create, --Destroy, --Label],
Rope USING [Cat, Concat, Equal, Index, ROPE, Substr],
UserCredentials USING [Get],
UserProfile USING [Boolean, ListOfTokens, Number, ProfileChangedProc, Token],
VFonts USING [EstablishFont, Font, FontHeight, StringWidth],
ViewerClasses USING [Viewer],
ViewerOps USING [DestroyViewer], -- should be Labels.Destroy
ViewerSpecs USING [openLeftWidth, openRightWidth],
ViewerTools USING [GetContents, SetContents];
DFToolUtilitiesImpl: CEDAR MONITOR
IMPORTS
Buttons, FS, IO, Labels, Rope, UserCredentials, UserProfile, VFonts, ViewerOps, ViewerSpecs, ViewerTools
EXPORTS DFToolInternal =
BEGIN
OPEN Tool: DFToolInternal;
ROPE: TYPE = Rope.ROPE;
---- ---- ---- ---- ---- ---- ---- ----
Global "Variables" (constant after init)
---- ---- ---- ---- ---- ---- ---- ----
userClasses: PUBLIC ARRAY Tool.UserClass OF ROPE
["Individual", "ReleaseParticipant", "ReleaseMaster"];
---- ---- ---- ---- ---- ---- ---- ----
Global Variables (protected by monitor)
---- ---- ---- ---- ---- ---- ---- ----
parameters: Tool.Parameters;
---- ---- ---- ---- ---- ---- ---- ----
Configuration Parameters (private)
---- ---- ---- ---- ---- ---- ---- ----
maxOps: NAT = 10;
---- ---- ---- ---- ---- ---- ---- ----
Utilities (exports to DFToolInternal for individual ops)
---- ---- ---- ---- ---- ---- ---- ----
AddOpToTable: PUBLIC PROC [definer: REF Tool.OpDefiner] = {
assumed to be called only before 'ReactToProfile' is enabled.
definer.opAlias ← GetOpAlias[definer.opName];
parameters.opTable.ops[parameters.opTable.nOps] ← definer;
parameters.opTable.nOps ← parameters.opTable.nOps.SUCC;
};
ViewerToRopeList: PUBLIC PROC [viewer: ViewerClasses.Viewer]
RETURNS [list: LIST OF ROPENIL] = {
tail: LIST OF ROPENIL;
s: IO.STREAM = IO.RIS[ViewerTools.GetContents[viewer]];
DO
r: ROPE ← s.GetTokenRope[IO.IDProc ! IO.EndOfStream => EXIT].token;
rL: LIST OF ROPE;
rL ← CONS[r, NIL];
IF list = NIL THEN list ← rL ELSE tail.rest ← rL;
tail ← rL;
ENDLOOP;
s.Close[];
};
EnsureDFName: PUBLIC PROC [r: ROPE] RETURNS [ROPE] = {
cp: FS.ComponentPositions;
fullFName: ROPENIL;
[fullFName, cp] ← FS.ExpandName[r ! FS.Error => CONTINUE];
IF fullFName ~= NIL AND cp.ver.length = 0 AND cp.ext.length = 0 THEN
r ← r.Concat[".df"];
RETURN[r]
};
LabelWidthForChoices: PUBLIC PROC [tool: Tool.DFTool, list: LIST OF Tool.Choice]
RETURNS [max: INT ← 0] = {
maxRope: ROPENIL;
temp: Labels.Label;
IF list = NIL THEN RETURN;
FOR l: LIST OF Tool.Choice ← list, l.rest UNTIL l = NIL DO
w: INT = VFonts.StringWidth[l.first.name];
IF w > max THEN {maxRope ← l.first.name; max ← w};
ENDLOOP;
temp ← Labels.Create[
info: [name: maxRope, wx: 0, wy: 0, parent: tool.outer, border: FALSE],
paint: FALSE
];
max ← temp.cw;
ViewerOps.DestroyViewer[viewer: temp, paint: FALSE]; -- Labels.Destroy[temp] repaints
};
MakeCenteredLabel: PUBLIC PROC [op: Tool.Operation, name: ROPE] = {
tool: Tool.DFTool = op.tool;
IF tool.parameters.compactLayout THEN RETURN;
[] ← Labels.Create[
info: [name: name,
wx: (OuterContainerWidth[tool] - VFonts.StringWidth[name])/2,
wy: op.height,
wh: tool.parameters.entryHeight,
parent: op.optionsContainer,
border: FALSE
],
font: tool.parameters.boldFont
];
op.height ← op.height + tool.parameters.entryHeight + tool.parameters.entryVSpace;
};
OuterContainerWidth: PUBLIC PROC [tool: Tool.DFTool] RETURNS [INT] = {
RETURN[
IF tool.outer.column = left THEN ViewerSpecs.openLeftWidth
ELSE ViewerSpecs.openRightWidth
]
};
CreateSelector: PUBLIC PROC [
name: ROPE, proc: Buttons.ButtonProc, clientData: REF ANY, choices: LIST OF Tool.Choice,
op: Tool.Operation, x: INTEGER ← -1]
RETURNS [selector: REF Tool.OptionSelector, newX: INTEGER] = {
tool: Tool.DFTool = op.tool;
button: Buttons.Button;
defaultOption: ROPE ← UserProfile.Token[Rope.Cat["DFTool.", op.definer.opAlias, ".", name]];
IF defaultOption = NIL THEN
defaultOption ← UserProfile.Token[Rope.Cat["DFTool.", op.definer.opName, ".", name]];
IF x < 0 THEN x ← tool.parameters.entryHSpace;
button ← Buttons.Create[
info: [name: name.Concat[":"],
wx: x,
wy: op.height,
wh: tool.parameters.entryHeight,
parent: op.optionsContainer, 
border: FALSE
],
proc: proc,
fork: FALSE,
clientData: clientData,
font: tool.parameters.font
];
selector ← NEW[Tool.OptionSelector ← [
name: name,
choices: choices,
default: choices.first.name
]];
IF defaultOption ~= NIL THEN
FOR l: LIST OF Tool.Choice ← choices, l.rest UNTIL l = NIL DO
IF defaultOption.Equal[l.first.name, FALSE] THEN {selector.default ← l.first.name; EXIT};
ENDLOOP;
selector.displayer ← Labels.Create[
info: [
name: selector.default,
wx: button.wx + button.ww + tool.parameters.entryHSpace,
wy: op.height,
wh: tool.parameters.entryHeight,
ww: LabelWidthForChoices[op.tool, choices],
parent: op.optionsContainer,
border: FALSE
],
font: tool.parameters.font
];
newX ← selector.displayer.wx + selector.displayer.ww;
};
SelectOption: PUBLIC PROC [selector: REF Tool.OptionSelector] RETURNS [choice: Tool.Choice] = {
NextChoice: PROC [this: ROPE, list: LIST OF Tool.Choice]
RETURNS [next: Tool.Choice ← [NIL, NIL]] = {
IF list = NIL THEN RETURN;
FOR l: LIST OF Tool.Choice ← list, l.rest UNTIL l = NIL DO
IF this.Equal[l.first.name, FALSE] THEN
RETURN[IF l.rest = NIL THEN list.first ELSE l.rest.first]
ENDLOOP;
RETURN[list.first]
};
choice ← NextChoice[ViewerTools.GetContents[selector.displayer], selector.choices];
ViewerTools.SetContents[selector.displayer, choice.name];
};
ResetOption: PUBLIC PROC [selector: REF Tool.OptionSelector] = {
ViewerTools.SetContents[selector.displayer, selector.default];
};
GetToolParameters: PUBLIC ENTRY PROC RETURNS [Tool.Parameters] = {RETURN[parameters]};
ReactToProfile: PUBLIC ENTRY UserProfile.ProfileChangedProc = {
It is important that the entire `parameters' data structure be copied, since there is unsynchronized access to its contents elsewhere in the tool. Since this will happen rarely, the cost is acceptable.
ENABLE UNWIND => NULL;
User profile fields:
DFTool.DFNamePrefixes: <list of file server prefixes>
DFTool.UserClass: {Individual, ReleaseParticipant, ReleaseMaster}
DFTool.NameFor<OpName>: synonym (where <OpName> is "BringOver", "SModel", etc.)
DFTool.FontFamily
DFTool.FontSize
DFTool.<OpName/OpSynonym>.<OptionName>: <defaultValue> (use "..." if embedded spaces)
DFTool.CompactLayout: TRUE | FALSE
params: Tool.Parameters ← NEW[Tool.ToolParameters];
fontFamily: ROPE = UserProfile.Token["DFTool.FontFamily", "Tioga"];
fontSize: NAT = UserProfile.Number["DFTool.FontSize", 10];
class: ROPE = UserProfile.Token[key: "DFTool.UserClass", default: userClasses[$individual]];
userName: ROPE ← UserCredentials.Get[].name;
IF reason = firstTime THEN RETURN; -- handled by initialization code, below.
userName ← userName.Substr[len: userName.Index[s2: "."]];
params.dfNamePrefixes ← UserProfile.ListOfTokens[
key: "DFTool.DFNamePrefixes",
default: LIST[
"[Indigo]<Cedar>Top>",
"[Indigo]<PreCedar>Top>",
Rope.Cat["[Ivy]<", userName, ">"]
]
];
params.userClass ← $individual;
FOR userClass: Tool.UserClass IN Tool.UserClass DO
IF class.Equal[userClasses[userClass], FALSE] THEN {params.userClass ← userClass; EXIT};
ENDLOOP;
params.opTable ← NEW[Tool.OpTable[maxOps]];
IF parameters = NIL THEN
params.opTable.nOps ← 0 -- called from this module's initialization; opTable filled in later
ELSE {
params.opTable.nOps ← parameters.opTable.nOps;
FOR op: NAT IN [0..parameters.opTable.nOps) DO
old: REF Tool.OpDefiner = parameters.opTable[op];
params.opTable.ops[op] ← NEW[Tool.OpDefiner ← [
opName: old.opName,
userClass: old.userClass,
proc: old.proc,
opAlias: GetOpAlias[old.opName]
]];
ENDLOOP;
};
params.compactLayout ← UserProfile.Boolean["DFTool.CompactLayout", FALSE];
params.font ← VFonts.EstablishFont[fontFamily, fontSize];
params.boldFont ← VFonts.EstablishFont[family: fontFamily, size: fontSize, bold: TRUE];
params.entryHeight ← VFonts.FontHeight[params.font] + 2;
params.entryVSpace ← VFonts.FontHeight[params.font]*1/3;
IF params.compactLayout THEN params.entryVSpace ← 1;
params.entryHSpace ← 10;
parameters ← params;
};
---- ---- ---- ---- ---- ---- ---- ----
Internal Procedures
---- ---- ---- ---- ---- ---- ---- ----
GetOpAlias: PROC [opName: ROPE] RETURNS [alias: ROPE] = {
RETURN[UserProfile.Token[Rope.Concat["DFTool.NameFor", opName], opName]]
};
---- ---- ---- ---- ---- ---- ---- ----
Initialization
---- ---- ---- ---- ---- ---- ---- ----
ReactToProfile[edit];
END.