DIRECTORY Buttons, Icons, IO, Menus, MJSContainers, PeanutProfile, PeanutWindow, PFS, PFSNames, Rope, Rules, TEditDocumentPrivate, TEditProfile, TextEdit, Tioga, TiogaIO, TiogaMenuOps, TiogaOps, TypeScript, VFonts, ViewerClasses, ViewerEvents, ViewerOps, ViewerSpecs, ViewerTools; PeanutWindowImpl: CEDAR MONITOR IMPORTS Buttons, Icons, IO, Menus, MJSContainers, PeanutProfile, PFS, PFSNames, Rope, Rules, TEditDocumentPrivate, TEditProfile, TextEdit, TiogaIO, TiogaMenuOps, TiogaOps, TypeScript, VFonts, ViewerEvents, ViewerOps, ViewerSpecs, ViewerTools EXPORTS PeanutWindow = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Viewer: TYPE = ViewerClasses.Viewer; Node: TYPE = Tioga.Node; peanutDestroyEvent: ViewerEvents.EventRegistration; peanutProp: ATOM = $PeanutMailFileName; newMailCaption: ROPE ~ "Peanut - You have new mail"; noNewMailCaption: ROPE ~ "Peanut - No new mail"; peanutParent: PUBLIC MJSContainers.MJSContainer ¬ NIL; peanutRule: Rules.Rule; peanutScript: TypeScript.TS; menu: PUBLIC Menus.Menu ¬ Menus.CreateMenu[2]; newMailIcon: PUBLIC Icons.IconFlavor ¬ Icons.NewIconFromFile["Peanut.icons", 0]; noMailIcon: PUBLIC Icons.IconFlavor ¬ Icons.NewIconFromFile["Peanut.icons", 1]; messageSetIcon: PUBLIC Icons.IconFlavor ¬ Icons.NewIconFromFile["Peanut.icons", 2]; dirtyMessageSetIcon: PUBLIC Icons.IconFlavor ¬ Icons.NewIconFromFile["Peanut.icons", 3]; mailMessageIcon: PUBLIC Icons.IconFlavor ¬ Icons.NewIconFromFile["Peanut.icons", 4]; dirtyMailMessageIcon: PUBLIC Icons.IconFlavor ¬ Icons.NewIconFromFile["Peanut.icons", 5]; maxButtonX: INTEGER ¬ 0; buttonX: INTEGER ¬ 0; newMailExists: BOOL ¬ FALSE; mjsClass: MJSContainers.MJSContainerClass ~ NEW[MJSContainers.MJSContainerClassRep ¬ [save: MySave]]; OutputRope: PUBLIC ENTRY PROC [text: ROPE] = { ENABLE UNWIND => NULL; IF ~Destroyed[] THEN TypeScript.PutRope[peanutScript, text]; }; OutputText: PUBLIC ENTRY PROC [text: REF READONLY TEXT] = { ENABLE UNWIND => NULL; IF ~Destroyed[] THEN TypeScript.PutText[peanutScript, text]; }; OutputChar: PUBLIC ENTRY PROC [char: CHAR] = { ENABLE UNWIND => NULL; IF ~Destroyed[] THEN TypeScript.PutChar[peanutScript, char]; }; SetNewMail: PUBLIC ENTRY PROC [newMail: BOOL] = { ENABLE UNWIND => NULL; IF newMailExists=newMail THEN RETURN; newMailExists ¬ newMail; IF Destroyed[] THEN RETURN; peanutParent.icon ¬ IF newMailExists THEN newMailIcon ELSE noMailIcon; peanutParent.name ¬ Caption[newMailExists]; ViewerOps.PaintViewer[peanutParent, caption]; }; AddCommand: PUBLIC ENTRY PROC [name: ROPE, proc: Menus.ClickProc, data: REF ANY ¬ NIL, fork: BOOL ¬ TRUE, guarded: BOOL ¬ FALSE, lineNum: Menus.MenuLine] = { ENABLE UNWIND => NULL; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name, proc, data, NIL, fork, guarded], lineNum]; IF peanutScript#NIL THEN ViewerOps.PaintViewer[peanutParent, all]; }; AddButton: PUBLIC ENTRY PROC [name: ROPE, proc: Menus.ClickProc, data: REF ANY ¬ NIL, fork: BOOL ¬ TRUE, guarded: BOOL ¬ FALSE, redisplay: BOOL ¬ TRUE] = { ENABLE UNWIND => NULL; buttonHeight: INTEGER = 15; buttonSpacing: INTEGER = 5; width: INTEGER; IF Destroyed[] THEN RETURN; width ¬ VFonts.StringWidth[name]+6; IF width+buttonX>maxButtonX THEN { ViewerOps.MoveViewer[peanutRule, peanutRule.wx, peanutRule.wy+buttonHeight, peanutRule.ww, peanutRule.wh, FALSE]; ViewerOps.MoveViewer[peanutScript, peanutScript.wx, peanutScript.wy+buttonHeight, peanutScript.ww, peanutScript.wh-buttonHeight, FALSE]; buttonX ¬ 0; peanutParent.openHeight ¬ peanutParent.openHeight+buttonHeight; }; [] ¬ Buttons.Create[info: [parent: peanutParent, name: name, wx: buttonX, wy: peanutRule.wy-buttonHeight, border: FALSE, scrollable: FALSE], proc: proc, clientData: data, fork: fork, guarded: guarded]; buttonX ¬ buttonX+width+buttonSpacing; IF ~peanutParent.iconic AND redisplay THEN ViewerOps.PaintViewer[peanutParent, all]; }; Create: PUBLIC ENTRY PROC [quit, save: PROC _ NIL] RETURNS [new: BOOL] = { ENABLE UNWIND => NULL; peanutOpenHeight: INTEGER; startIconic: BOOL; quitProc _ quit; saveProc _ save; IF ~Destroyed[] THEN RETURN [FALSE]; -- already exists maxButtonX ¬ ViewerSpecs.openRightWidth-ViewerSpecs.scrollBarW-4; peanutOpenHeight ¬ PeanutProfile.windowHeight; startIconic ¬ PeanutProfile.startIconic; peanutParent ¬ MJSContainers.Create[$PeanutContainer, [name: Caption[newMailExists], iconic: startIconic, icon: IF newMailExists THEN newMailIcon ELSE noMailIcon, column: right, openHeight: peanutOpenHeight, menu: menu, scrollable: FALSE]]; peanutRule ¬ Rules.Create[[parent: peanutParent, wx: 0, wy: 0, ww: maxButtonX, wh: 1, scrollable: FALSE, border: FALSE]]; peanutScript ¬ TypeScript.Create[[parent: peanutParent, wx: 0, wy: peanutRule.wy+peanutRule.wh, ww: maxButtonX, wh: 60, scrollable: TRUE, border: FALSE]]; peanutDestroyEvent ¬ ViewerEvents.RegisterEventProc[proc: QuitProc, event: destroy, filter: peanutParent, before: FALSE]; MJSContainers.ChildXBound[peanutParent, peanutRule]; MJSContainers.ChildXBound[peanutParent, peanutScript]; MJSContainers.ChildYBound[peanutParent, peanutScript]; buttonX ¬ LAST[INTEGER]/2; RETURN [TRUE]; }; quitProc, saveProc: PROC _ NIL; Destroy: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; IF ~Destroyed[] THEN ViewerOps.DestroyViewer[peanutParent]; peanutParent ¬ peanutScript ¬ NIL; }; QuitProc: ViewerEvents.EventProc = { IF ( peanutParent # NIL ) AND ( peanutDestroyEvent # NIL ) THEN { peanutParent ¬ NIL; peanutScript ¬ NIL; ViewerEvents.UnRegisterEventProc[peanutDestroyEvent, destroy]; peanutDestroyEvent ¬ NIL; IF quitProc # NIL THEN quitProc[]; }; RETURN[FALSE]; }; Destroyed: PROC RETURNS [destroyed: BOOL] = { IF peanutParent = NIL THEN RETURN [TRUE] ELSE IF peanutParent.destroyed THEN { peanutParent ¬ peanutScript ¬ NIL; RETURN [TRUE] }; RETURN [FALSE]; }; Caption: PROC [newMail: BOOL] RETURNS [name: ROPE] = { IF newMail THEN RETURN[newMailCaption] ELSE RETURN[noNewMailCaption]; }; SaveAllMailFiles: PUBLIC PROC [mailFiles: LIST OF ROPE, killViewers: BOOL] ~ { once: BOOL ¬ FALSE; FOR files: LIST OF ROPE ¬ mailFiles, files.rest UNTIL files = NIL DO viewer: Viewer ¬ FindMailViewer[files.first]; IF viewer # NIL THEN { IF viewer.newVersion THEN { IF NOT once THEN {OutputRope["\nSaving "]; once ¬ TRUE}; OutputRope[files.first]; OutputChar[' ]; [] ¬ ViewerOps.SaveViewer[viewer]; }; IF killViewers THEN ViewerOps.DestroyViewer[viewer]; }; ENDLOOP; IF once THEN OutputRope["(done)"]; IF killViewers THEN ViewerOps.CloseViewer[peanutParent]; }; MySave: PROC [self: ViewerClasses.Viewer, force: BOOL] -- ViewerClasses.SaveProc -- ~ { IF saveProc # NIL THEN saveProc[]; }; SetMailFileName: PROC[v: Viewer, name: ROPE] = { ViewerOps.AddProp[viewer: v, prop: peanutProp, val: name]; ViewerOps.AddProp[viewer: v, prop: $IconLabel, val: v.label]; }; GetMailFileName: PROC[v: Viewer] RETURNS[ROPE] = { WITH ViewerOps.FetchProp[viewer: v, prop: peanutProp] SELECT FROM rope: ROPE => RETURN[rope]; ENDCASE => RETURN[NIL]; }; FindMailViewer: PUBLIC PROC[name: ROPE] RETURNS[viewer: Viewer ¬ NIL] = { Test: ViewerOps.EnumProc -- PROC[v: Viewer] RETURNS[continue: BOOL ¬ TRUE] -- = { rope: ROPE = GetMailFileName[v]; IF rope#NIL AND Rope.Equal[rope, name, FALSE] THEN { viewer ¬ v; RETURN[FALSE] }; }; ViewerOps.EnumerateViewers[Test]; }; GetMailViewer: PUBLIC ENTRY PROC[name: ROPE] RETURNS [mailViewer: Viewer] = { ENABLE UNWIND => NULL; mailViewer ¬ InternalGetMailViewer[name]; }; InternalGetMailViewer: PUBLIC INTERNAL PROC [name: ROPE] RETURNS [v: Viewer] ~ { v ¬ FindMailViewer[name]; IF v=NIL THEN { wDir: ROPE ¬ PeanutProfile.workingDirectory; shortName: ROPE ¬ name.Concat[".mail"]; longNamePath: PFS.PATH ¬ PFSNames.ExpandName[name: PFS.PathFromRope[shortName], wDir: PFS.PathFromRope[wDir]]; fileName: ROPE ¬ PFS.RopeFromPath[longNamePath]; mailDoc: Node ¬ NIL; strm: IO.STREAM; strm ¬ PFS.StreamOpen[longNamePath ! PFS.Error => IF error.code=$unknownFile THEN CONTINUE]; IF strm = NIL THEN { styleProp: ROPE = "(mail) style"; mailDoc ¬ TextEdit.DocFromNode[TextEdit.FromRope[shortName]]; TiogaOps.PutProp[mailDoc, $Prefix, styleProp]; } ELSE { strm.Close[]; mailDoc ¬ TiogaIO.FromFile[PFS.PathFromRope[fileName]].root; }; v ¬ ViewerTools.MakeNewTextViewer[info: [ name: fileName, file: fileName, label: name, data: mailDoc, icon: messageSetIcon, iconic: TRUE], paint: FALSE]; SetMailFileName[v, name]; ViewerOps.PaintViewer[v, all]; [] ¬ ViewerEvents.RegisterEventProc[proc: MessageSetHasBeenOpened, event: open, filter: v, before: TRUE]; [] ¬ ViewerEvents.RegisterEventProc[proc: MessageSetHasBeenEdited, event: edit, filter: v, before: TRUE]; [] ¬ ViewerEvents.RegisterEventProc[proc: MessageSetHasBeenSaved, event: save, filter: v, before: FALSE]; TiogaMenuOps.DefaultMenus[v]; IF TEditProfile.menu1 # levels AND TEditProfile.menu2 # levels AND TEditProfile.menu3 # levels THEN TEditDocumentPrivate.LevelMenu[v]; TiogaMenuOps.FirstLevelOnly[v]; }; }; MessageSetHasBeenOpened: PROC[viewer: Viewer, event: ViewerEvents.ViewerEvent, before: BOOL] RETURNS[abort: BOOL ¬ FALSE] = { IF PeanutProfile.automaticNewMail AND NOT viewer.destroyed THEN SetNewMail[FALSE]; }; MessageSetHasBeenEdited: PROC[viewer: Viewer, event: ViewerEvents.ViewerEvent, before: BOOL] RETURNS[abort: BOOL ¬ FALSE] = { IF before THEN { viewer.icon ¬ dirtyMessageSetIcon; IF viewer.iconic THEN ViewerOps.PaintViewer[viewer: viewer, hint: all]; }; }; MessageSetHasBeenSaved: PROC [viewer: Viewer, event: ViewerEvents.ViewerEvent, before: BOOL] RETURNS[abort: BOOL ¬ FALSE] = { IF NOT before THEN { viewer.icon ¬ messageSetIcon; IF viewer.iconic THEN ViewerOps.PaintViewer[viewer: viewer, hint: all]; }; }; CopyMessages: PUBLIC PROC [to: ROPE, delete: BOOL] = { sourceViewer, destViewer: Viewer; destDoc, sourceDoc, destLast, sourceLast, afterSource: Node; start, end: TiogaOps.Location; level: TiogaOps.SelectionGrain; caretBefore, pendingDelete: BOOL; lockedPrimary, lockedSecondary, lockedDest, lockedSource: BOOL ¬ FALSE; TopParent: PROC [node, root: Node] RETURNS [parent: Node] = { DO parent ¬ TiogaOps.Parent[node]; IF parent=root THEN RETURN [node]; node ¬ parent; ENDLOOP; }; Cleanup: PROC = { IF lockedPrimary THEN TiogaOps.UnlockSel[primary]; IF lockedSecondary THEN TiogaOps.UnlockSel[secondary]; IF lockedDest THEN TiogaOps.Unlock[destDoc]; IF lockedSource THEN TiogaOps.Unlock[sourceDoc]; }; destViewer ¬ GetMailViewer[to]; TiogaOps.LockSel[primary]; lockedPrimary ¬ TRUE; [sourceViewer, start, end, level, caretBefore, pendingDelete] ¬ TiogaOps.GetSelection[]; IF sourceViewer=NIL OR sourceViewer.class.flavor#$Text THEN { TiogaOps.UnlockSel[primary]; OutputRope["\nSelect message(s)."]; RETURN }; TiogaOps.LockSel[secondary]; lockedSecondary ¬ TRUE; destDoc ¬ TiogaOps.ViewerDoc[destViewer]; TiogaOps.Lock[destDoc]; lockedDest ¬ TRUE; sourceDoc ¬ TiogaOps.ViewerDoc[sourceViewer]; IF sourceDoc#destDoc THEN { TiogaOps.Lock[sourceDoc]; lockedSource ¬ TRUE }; destLast ¬ TiogaOps.LastChild[destDoc]; sourceLast ¬ TopParent[end.node, sourceDoc]; afterSource ¬ TiogaOps.Next[sourceLast]; TiogaOps.SelectBranches[ -- source viewer: sourceViewer, level: branch, caretBefore: FALSE, pendingDelete: delete, which: primary, start: TopParent[start.node, sourceDoc], end: sourceLast]; TiogaOps.SelectBranches[ -- destination viewer: destViewer, start: destLast, end: destLast, level: branch, caretBefore: FALSE, pendingDelete: FALSE, which: secondary]; TiogaOps.ToSecondary[]; IF NOT delete THEN -- restore original selection TiogaOps.SetSelection[sourceViewer, start, end, level, caretBefore, pendingDelete, primary] ELSE IF afterSource # NIL THEN TiogaOps.SelectPoint[sourceViewer, [afterSource,0], primary] ELSE TiogaOps.CancelSelection[primary]; Cleanup[]; OutputRope[IF delete THEN "\nMoved to " ELSE "\nCopied to "]; OutputRope[to]; }; MJSContainers.RegisterClass[$PeanutContainer, mjsClass]; END. PeanutWindowImpl.mesa Copyright Σ 1984, 1985, 1988, 1990, 1992 by Xerox Corporation. All rights reserved. Written by Scott McGregor, February 1983 Last edited by Paxton on March 1, 1983 8:59 am Last edited by McGregor on March 4, 1983 9:55 am Last Edited by: Pausch, July 14, 1983 2:28 pm Last Edited by: Wyatt, April 9, 1985 2:04:54 pm PST Willie-Sue, December 5, 1989 12:34:39 pm PST Last changed by Pavel on March 8, 1990 1:47 pm PST Jules Bloomenthal July 1, 1992 1:38 pm PDT Doug Wyatt, July 10, 1992 12:29 pm PDT Types Globals Access to top level Peanut viewer PeanutRetrieve.CloseConnection[]; Message Transfer Enumerate top level viewers, looking for one with a matching $PeanutMailFile property Make this an entry so don't have two Get's at once for same mail file Start Code Κ ¨–(cedarcode) style•NewlineDelimiter ˜– "Cedar" stylešœ™J– "Cedar" stylešœ ΟeœI™TJ– "Cedar" stylešœ(™(Jšœ.™.Jšœ0™0J™-J™3J™,J™2J™*J™&—J˜IcodešΟk œžœ5žœΔ˜˜J˜šΠblœžœž˜Kšžœžœ'žœ­˜ρKšžœ ˜K˜—Jšœž˜headšΟl™Jšžœž œžœ˜Jšžœž œžœžœ˜Jšœž œ˜(Jšœ žœ˜J˜3—š ™Jšœ žœ˜*Jšœžœ"˜7Jšœžœ˜3Jšœ ž œžœ˜8J˜Jšœžœ˜J˜Jšœž œ"˜3J˜Jšœ ž œ=˜RJšœ ž œ=˜RJšœž œ=˜UJšœžœ=˜XJšœžœ=˜UJšœžœ=˜YJ˜Jšœžœ˜Jšœ žœ˜J˜Jšœžœžœ˜J˜˜/Jšž œ6˜@——š !™!š Οn œžœžœžœžœ˜.Jšžœžœžœ˜Jšžœžœ(˜˜>Jšœžœ˜Jšžœ žœžœ ˜"Jšœ!™!J˜—Jšžœžœ˜J˜—J˜š‘ œžœžœ žœ˜-š žœžœžœžœžœ˜(šžœžœžœ˜%Jšœžœ˜"Jšžœžœ˜ Jšœ˜——Jšžœžœ˜Jšœ˜—J˜š ‘œžœ žœžœžœ˜6Jš žœ žœžœžœžœ˜EJšœ˜—J˜š‘œžœžœ žœžœžœžœ˜NJšœžœžœ˜š žœžœžœžœžœ žœž˜DJ˜-šžœ žœžœ˜šžœžœ˜Jšžœžœžœ"žœ˜8J˜J˜J˜"J˜—Jšžœ žœ!˜4Jšœ˜—Jšžœ˜—Jšžœžœ˜"Jšžœ žœ%˜8J˜J˜—š‘œžœ%žœ’œ˜WJšžœ žœžœ ˜"J˜——š ™š‘œžœžœ˜0Kšœ:˜:Kšœ=˜=K˜K˜—š‘œžœ žœžœ˜2šžœ2žœž˜AKšœžœžœ˜Kšžœžœžœ˜—K˜K˜—š ‘œžœžœžœžœžœ˜IKšœU™Ušœ’*œ’ œ˜QKšœžœ˜ Kšžœžœžœžœžœžœžœ˜QK˜—K˜!K˜K˜—š ‘ œžœž œžœžœ˜MK™EKšžœžœžœ˜K˜)K˜K˜—š‘œΟsžΠksž€žœžœ£žœ £œ£œ˜PK˜šžœžœžœ˜Kšœžœ"˜,Kšœ žœ˜'Kš œžœžœžœ žœ˜nKšœ žœžœ˜0Kšœžœ˜Kšœžœžœ˜Kš œžœžœ žœžœžœ˜\šžœžœžœ˜Kšœ žœ˜!K˜=Kšœ.˜.K˜šžœ˜K˜ Kšœžœ˜