<> <> <> <> <> <> <> <> <> <> <> DIRECTORY Atom USING [GetPropFromList], Buttons, Containers, DB, DBIcons USING [GetIcon], DBNames USING[MakeName, NameToEntity], DefaultNutUtilities, --EntityEditor, Icons USING [IconFlavor, NewIconFromFile], InputFocus USING [SetInputFocus], IO, Menus USING [AppendMenuEntry, CreateMenu, Menu, MenuProc, SetGuarded, FindEntry], NoteEditor, Nut, NutButtons, NutOps, NutViewer, Rope, SafeStorage USING [NarrowRefFault], TiogaOps USING [InsertRope], TuplesEditor, ViewerLocks, ViewerOps, ViewerClasses, ViewerTools; NutDefaultImpl: CEDAR PROGRAM IMPORTS Atom, DB, DBIcons, DBNames, DefaultNutUtilities, InputFocus, IO, Nut, NutOps, NutViewer, Icons, Menus, NoteEditor, Rope, SafeStorage, TiogaOps, TuplesEditor, ViewerOps, ViewerTools SHARES ViewerLocks = BEGIN OPEN DB, NutViewer, ViewerClasses; Viewer: TYPE = ViewerClasses.Viewer; <> editorMenu: Menus.Menu _ Menus.CreateMenu[]; <> <> ConvertViewerToEntity: PROC[v: Viewer, create: BOOL _ FALSE] RETURNS[e: Entity, name: ROPE] = BEGIN eName, domain: ROPE; segment: DB.Segment; [segment, domain, eName] _ Nut.GetNutInfo[v]; IF segment = NIL THEN RETURN; name _ DBNames.MakeName[segment, domain, eName]; e _ DBNames.NameToEntity[name, create] END; FreezeProc: Menus.MenuProc = { [] _ Nut.SetFrozenProperty[NARROW[parent], TRUE] }; ResetProc: Menus.MenuProc = BEGIN <> viewer: Viewer = NARROW[parent]; seg: Segment; domain: ROPE; eName: ROPE; [seg, domain, eName] _ Nut.GetNutInfo[viewer]; InputFocus.SetInputFocus[]; -- kill the caret viewer.child _ NIL; TuplesEditor.ResetTuples[viewer]; ViewerOps.PaintViewer[viewer, $all]; [] _ DefaultEdit[eName: eName, domain: domain, segment: seg, lastSpawned: viewer]; Menus.SetGuarded[ Menus.FindEntry[viewer.menu, "Reset"], FALSE ]; END; SaveProc: Menus.MenuProc = BEGIN <> viewer: Viewer = NARROW[parent]; newV: Viewer; seg: Segment; d: Domain; dName: ROPE; eName: ROPE; e: Entity; [seg, dName, eName]_ Nut.GetNutInfo[viewer]; d _ DB.DeclareDomain[dName, seg]; e _ DB.DeclareEntity[d, eName, NewOrOld ]; TRUSTED BEGIN --entityRow: VTable = GetTableEntry[ table: table, row: 2 ]; notes: Viewer = NARROW[ ViewerOps.FetchProp[viewer, $Notes]]; errors: BOOL_ TuplesEditor.SaveTuples[viewer: notes, newEntity: e].errors; --EntityEditor.SaveEntities[viewer: entityRow, newOf: e]; NoteEditor.SaveNote[newEntity: e, viewer: notes, update: TRUE]; <> IF errors THEN NutViewer.Message[viewer, "You may correct any errors and save again."] ELSE BEGIN newV _ NutViewer.ReplaceViewer[eName: eName, domain: dName, seg: seg, parent: viewer]; [] _ DefaultDisplay[eName: eName, domain: dName, segment: seg, lastSpawned: newV]; END; END; END; MergeProc: Menus.MenuProc = BEGIN <> <> <> viewer: Viewer = NARROW[parent]; seg: Segment; d: Domain; dName: ROPE; eName: ROPE; e: Entity; otherEntity: Entity; otherName: ROPE = ViewerTools.GetSelectionContents[]; [seg, dName, eName] _ Nut.GetNutInfo[viewer]; d _ DB.DeclareDomain[dName, seg]; otherEntity _ IF otherName=NIL THEN NIL ELSE DB.FetchEntity[d, otherName, seg]; e_ DB.FetchEntity[d, eName, seg ! DB.Error => { e _ NIL; CONTINUE } ]; IF e = NIL THEN Message[viewer, "This entity does not exist yet!"] ELSE IF otherName=NIL THEN Message[viewer, "Please select name for entity to merge with!"] ELSE IF otherEntity=NIL THEN Message[viewer, "Selected entity not found in this domain!"] ELSE TRUSTED BEGIN displayViewer: Viewer = viewer.child; newV: Viewer; NutViewer.Message[ viewer, "Copying ", eName, " to ", Rope.Concat[otherName, ", and deleting it..."]]; []_ TuplesEditor.MergeTuples[viewer: displayViewer, newEntity: otherEntity]; --EntityEditor.SaveEntities[viewer: entityRow, newOf: otherEntity]; NoteEditor.SaveNote[newEntity: otherEntity, update: TRUE, viewer: NARROW[ViewerOps.FetchProp[viewer, $Notes], Viewer] ]; DB.DestroyEntity[e]; -- Get rid of old entity, its relationships have been moved newV _ NutViewer.ReplaceViewer[eName: eName, domain: dName, seg: seg, parent: viewer]; [] _ DefaultDisplay[eName: eName, domain: dName, segment: seg, lastSpawned: newV]; END; END; RenameProc: Menus.MenuProc = { ENABLE DB.Error => IF code=NonUniqueEntityName THEN {NutViewer.Message[NARROW[parent], "Entity already exists with that name!"]; CONTINUE}; viewer: Viewer = NARROW[parent]; seg: Segment; d: Domain; dName: ROPE; eName: ROPE; e: Entity; newName: ROPE = ViewerTools.GetSelectionContents[]; [seg, dName, eName]_ Nut.GetNutInfo[viewer]; d _ DB.DeclareDomain[dName, seg]; e_ DB.FetchEntity[d, eName, seg ]; IF e = NIL THEN Message[viewer, "Entity does not exist yet!"] ELSE IF newName=NIL THEN Message[viewer, "Please select new name for entity first!"] ELSE { DB.ChangeName[e, newName]; ViewerOps.AddProp[viewer, $EntityName, newName]; ViewerOps.AddProp[viewer, $Entity, e]; viewer.name_ Rope.Cat[NutOps.SafeNameOf[d],": ", newName]; ViewerOps.PaintViewer[viewer, caption] }; }; EraseAllProc: Menus.MenuProc = { viewer: Viewer = NARROW[parent]; seg: Segment; d: Domain; dName: ROPE; eName: ROPE; e: Entity; [seg, dName, eName]_ Nut.GetNutInfo[viewer]; d _ DB. DeclareDomain[dName, seg]; e_ DB.FetchEntity[d, eName, seg ! DB.Error => { e _ NIL; CONTINUE } ]; IF e = NIL THEN RETURN; DB.DestroyEntity[e]; ViewerOps.DestroyViewer[viewer]; }; <<-- looks like AddProc is for adding icons to the related entities list>> AddProc: Menus.MenuProc = TRUSTED { viewer: Viewer = NARROW[parent]; entityRow: Viewer = viewer.child; selected: Viewer = ViewerTools.GetSelectedViewer[]; entity: Entity; IF selected=NIL THEN {NutViewer.Error[viewer, "No viewer selected!"]; RETURN}; entity_ ConvertViewerToEntity[ParentOf[selected]].e; --EntityEditor.NewEntry[ entity, entityRow ]; }; <<-------------------------->> ParentOf: PROC[ v: Viewer ] RETURNS[ parent: Viewer ] = { parent _ v; WHILE parent.parent # NIL DO parent _ parent.parent ENDLOOP }; DefaultEdit: PUBLIC Nut.NutProc = TRUSTED BEGIN d: Domain = DB.DeclareDomain[domain, segment]; al: LIST OF Attribute = NutOps.GetRefAttributes[d]; <> e: DB.Entity; newV: ViewerClasses.Viewer = NutViewer.CreateDefaultViewer[replace: lastSpawned, domain: domain, eName: eName, segment: segment]; e _ DeclareEntity[d, eName, OldOnly]; ViewerOps.SetMenu[newV, editorMenu]; newV.child _ NIL; ViewerOps.PaintViewer[newV, all]; [] _ TuplesEditor.DisplayTuples[e, al, newV]; [] _ NoteEditor.DisplayNote[entity: e, sibling: newV.child, segment: segment]; RETURN[newV] END; <> displayerMenu: Menus.Menu _ Menus.CreateMenu[]; DefaultDisplay: PUBLIC Nut.NutProc = TRUSTED BEGIN lastViewer: Viewer; d: DB.Domain = DB.DeclareDomain[domain, segment]; e: DB.Entity _ DB.FetchEntity[d, eName, segment]; newV: ViewerClasses.Viewer = NutViewer.CreateDefaultViewer[replace: lastSpawned, domain: domain, eName: eName, segment: segment]; ViewerOps.SetMenu[newV, displayerMenu]; lastViewer_ BuildTupleWindowButtons[e, segment, newV]; [] _ NoteEditor.DisplayNote[entity: e, sibling: lastViewer, segment: segment, noEdits: TRUE]; ViewerOps.PaintViewer[newV, all]; RETURN[newV] END; BuildTupleWindowButtons: PROC[e: Entity, seg: Segment, v: Viewer] RETURNS [Viewer] = BEGIN alT: AttributeList; t: Relship; myRel: Relation; tuples: RelshipSet; lastButton: Viewer; myAttrs: AttributeList; myAttrs_ RemoveSpecialAttributesFrom[DB.GetAllRefAttributes[e], seg]; lastButton_ NutViewer.Initialize[v]; FOR alT_ myAttrs, alT.rest UNTIL alT=NIL DO skipRelationName: BOOL _ FALSE; lastRelButton: Viewer _ NIL; IF Null[alT.first] THEN LOOP; myRel_ V2E[GetP[alT.first, aRelationIs]]; tuples_ RelationSubset[myRel, LIST[[alT.first, e]]]; IF NutOps.RSetSize[RelationSubset[myRel, LIST[[alT.first, e]]]]#9999 THEN UNTIL Null[t_ NextRelship[tuples]] DO [lastRelButton, lastButton] _BuildTuplesButtons[ v, alT.first, myRel, t, lastButton, skipRelationName, lastRelButton]; IF skipRelationName = FALSE THEN skipRelationName _ TRUE; ENDLOOP ELSE BuildMultiTupleButtons[v, alT.first, myRel, tuples]; ReleaseRelshipSet[tuples]; ENDLOOP; RETURN[lastButton] END; BuildMultiTupleButtons: PROC[viewer: Viewer, a: Attribute, r: Relation, ts: RelshipSet] = <> {Message[viewer, "Too many ", GetName[r], "s to display"]}; BuildTuplesButtons: PROC[ v: Viewer, a: Attribute, r: Relation, t: Relship, lastButton: Viewer, skipRelButton: BOOL _ FALSE, lastRelButton: Viewer _ NIL] RETURNS[Viewer, Viewer] = <> BEGIN aValue: ROPE; al: AttributeList_ NutOps.RemoveAttribute[a, DB.VL2EL[DB.GetPList[r, aRelationOf]]]; relationButton: Viewer; IF skipRelButton THEN lastButton _ ButtonCopy[lastRelButton] ELSE lastButton_ MakeButton[ q: DBQueue[], name: GetName[r], proc: ProcessSelection, data: r, sib: lastButton, newLine: TRUE]; relationButton _ lastButton; FOR alT: AttributeList_ al, alT.rest UNTIL alT=NIL DO aValue_ GetFS[t, alT.first]; IF aValue.Length[]>0 THEN -- only print if non-null value lastButton_ MakeButton[ q: DBQueue[], name: Rope.Cat[GetName[alT.first], ": ", aValue], proc: ProcessSelection, sib: lastButton, data: GetF[t, alT.first], font: NEW[NutButtons.ButtonFontInfoRec _ [TRUE,,,]] ]; ENDLOOP; RETURN[relationButton, lastButton]; END; ButtonCopy: PROC[lastRelButton: Viewer] RETURNS[Viewer] = BEGIN newV: Viewer _ NEW[ViewerRec]; newV.wy _ lastRelButton.wy + lastRelButton.wh; newV.wx _ lastRelButton.wx; newV.ww _ lastRelButton.ww; newV.wh _ lastRelButton.wh; newV.parent _ lastRelButton.parent; RETURN[newV]; END; RemoveSpecialAttributesFrom: PROC [ old: LIST OF Attribute, seg: Segment] RETURNS[new: LIST OF Attribute] = { <> ENABLE DB.Error => {IF code=NotFound THEN {new_ old; CONTINUE}}; star: Relation = DeclareRelation["*", seg, OldOnly]; starOf: Attribute = DeclareAttribute[r: star, name: "of", version: OldOnly]; starIs: Attribute = DeclareAttribute[r: star, name: "is", version: OldOnly]; note: Relation = DeclareRelation["note", seg, OldOnly]; noteOf: Attribute = DeclareAttribute[r: note, name: "of", version: OldOnly]; new_ old; IF star # NIL THEN {new_ NutOps.RemoveAttribute[starOf, new]; new_ NutOps.RemoveAttribute[starIs, new]}; IF note # NIL THEN new _ NutOps.RemoveAttribute[noteOf, new]; RETURN[new] }; EditProc: Menus.MenuProc = BEGIN <> <> viewer: Viewer = NARROW[parent]; seg: DB.Segment; dName: ROPE; eName: ROPE; [seg, dName, eName]_ Nut.GetNutInfo[viewer]; [] _ DefaultEdit[ eName: eName, domain: dName, segment: seg, lastSpawned: viewer]; END; PasteNameProc: Menus.MenuProc = { viewer: Viewer = NARROW[parent]; eName: ROPE_ Nut.GetNutInfo[viewer].entity; TiogaOps.InsertRope[eName]; }; <> queryerMenu: Menus.Menu _ Menus.CreateMenu[]; queryerIcon: Icons.IconFlavor_ Icons.NewIconFromFile["Nut.Icons", 11]; qNumber: INT_ 0; entryHeight: INTEGER = 14; NextQNumber: PROC RETURNS[INT] = { RETURN[qNumber_ qNumber + 1] }; DefaultQuery: PUBLIC Nut.NutProc = BEGIN al: AttributeList; d: DB.Domain = DB.DeclareDomain[domain, segment]; newV: ViewerClasses.Viewer; IF DB.IsSystemEntity[d] THEN {Message[newV, "Query not allowed on system domains!"]; RETURN[NIL]}; newV _ NutViewer.CreateDefaultViewer[replace: lastSpawned, domain: domain, eName: eName, segment: segment]; ViewerOps.SetMenu[newV, queryerMenu]; newV.icon_ queryerIcon; al_ DB.GetDomainRefAttributes[d]; [] _ TuplesEditor.DisplayTuples[NIL, al, newV]; RETURN[newV] END; QueryProc: Menus.MenuProc = BEGIN <> <> viewer: Viewer = NARROW[parent]; seg: Segment_ NARROW[ViewerOps.FetchProp[viewer, $Segment] ]; dName: ROPE = V2S[ ViewerOps.FetchProp[viewer, $DomainName] ]; d: Domain = DeclareDomain[dName, seg]; number: INT = NextQNumber[]; answer: LIST OF Entity_ TuplesEditor.QueryTuples[viewer: viewer]; IF answer=NIL THEN Message[viewer, "No entities satisfied query!"] ELSE IF answer.rest=NIL THEN BEGIN Message[viewer, "One entity satisfied query; displaying it..."]; [] _ Nut.Display[eName: DB.NameOf[answer.first], domain: dName, segment: seg, parent: viewer]; END ELSE BEGIN Message[ viewer, "Entities satisfying query displayed in Answer viewer..."]; MultiDisplay[ entities: answer, title: IO.PutFR["Answer to %g query #%g", IO.rope[dName], IO.int[number]], icon: DBIcons.GetIcon[iconName: dName, default: queryerIcon] ]; END; END; MultiDisplay: PROC[entities: LIST OF Entity, title: ROPE, icon: Icons.IconFlavor] = BEGIN v, lastButton: Viewer; v_ ViewerOps.CreateViewer[ flavor: $Container, info: [name: title, iconic: FALSE, icon: icon], paint: FALSE]; lastButton_ NutViewer.Initialize[v]; FOR elT: LIST OF Entity_ entities, elT.rest UNTIL elT=NIL DO e: Entity= elT.first; lastButton _ NutViewer.MakeButton[ q: DBQueue[], name: GetName[e], proc: ProcessSelection, data: e, sib: lastButton, newLine: TRUE]; ENDLOOP; ViewerOps.PaintViewer[v, all] END; ProcessSelection: Menus.MenuProc = <> <> BEGIN viewer: ViewerClasses.Viewer _ NARROW[parent]; IF shift THEN <> TiogaOps.InsertRope[Rope.Substr[viewer.name, Rope.Find[viewer.name, ":"]+2]] ELSE BEGIN e: Entity_ V2E[clientData ! SafeStorage.NarrowRefFault => GO TO NotEntity]; <> FOR viewer _ viewer, viewer.parent UNTIL viewer.parent=NIL DO ENDLOOP; [] _ Nut.Display[eName: DB.NameOf[e], domain: DB.NameOf[DB.DomainOf[e]], segment: Nut.GetNutInfo[viewer].segment, parent: DefaultNutUtilities.GetTopLevel[viewer] ]; EXITS NotEntity => NutViewer.Message[viewer, "Not an entity-valued field!"]; END; END; ClearProc: Menus.MenuProc = BEGIN -- Resets contents of queryer . viewer: Viewer = NARROW[parent]; dName: ROPE; seg: Segment; d: Domain; al: AttributeList; [seg, dName,] _ Nut.GetNutInfo[viewer]; d _ DeclareDomain[dName, seg]; al _ DB.GetDomainRefAttributes[d]; InputFocus.SetInputFocus[]; -- kill the caret viewer.child _ NIL; TuplesEditor.ResetTuples[viewer]; ViewerOps.PaintViewer[viewer, $client]; [] _ TuplesEditor.DisplayTuples[NIL, al, viewer]; Menus.SetGuarded[ Menus.FindEntry[viewer.menu, "Clear"], FALSE ]; END; <> Menus.AppendMenuEntry[ displayerMenu, MakeMenuEntry[DBQueue[], "Edit", EditProc]]; Menus.AppendMenuEntry[ displayerMenu, MakeMenuEntry[DBQueue[], "Freeze", FreezeProc]]; Menus.AppendMenuEntry[ displayerMenu, MakeMenuEntry[DBQueue[], "Paste", PasteNameProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Freeze", FreezeProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Paste", PasteNameProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Reset", ResetProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Save", SaveProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Rename", RenameProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Merge", MergeProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "EraseAll", EraseAllProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "AddSelected", AddProc]]; Menus.AppendMenuEntry[ queryerMenu, MakeMenuEntry[DBQueue[], "Query", QueryProc]]; Menus.AppendMenuEntry[ queryerMenu, MakeMenuEntry[DBQueue[], "Clear", ClearProc]]; Nut.Register[ NIL, NIL, DefaultDisplay, DefaultEdit, DefaultQuery ]; END. Change log [since copied some of this code into Walnut]: Cattell March 18, 1982 1:48 pm: Palm updates Cattell April 6, 1983 11:17 am: re-insert default displayer from old NutViewerDefaultImpl: Jim's editor is now default editor, old displayer is default displayer. No default queryer yet. Use VTables for the BuildTupleWindowButtons. Cattell April 7, 1983 11:58 am: various fixes everywhere. Cattell April 15, 1983 11:41 am: added Rename, Merge, EraseAll, etc. Not all checked yet. Changed "Remove" to EraseAll, as it erases all rather than what a user might think it does, i.e. removing one of the related entities. Cattell May 30, 1983 4:15 pm: added message subwindow to editor, fixed up icon for queryer, fixed some error conditions in editor, etc. Cattell June 22, 1983 3:49 pm: bug in RemoveSpecialAttributesFrom Cattell July 5, 1983 5:17 pm: fixed NutImpl and all procs to uniformly use a $NutType, $DomainName, $EntityName, and $Segment prop associated with all nut viewers. Butler June 26, 1984: Minor changes due to reorganization of Nut. Defaults now register with Nut instead of Nut knowing about them.