<> <> <> <> <<(Changed the implementation so that this interface never catches any errors -- they will all be caught at the WhiteboardDB level and turned into WBErrors)>> <<(Added Grid size property to whiteboards)>> <<(Added create date property)>> <> DIRECTORY AlpTransaction, Atom, BasicTime, DB, DBCommon, DBDefs, FileNames USING[GetShortName], IO USING [PutR, card], Rope, TextFind, ViewerTools, WhiteboardDBPrivate; WhiteboardDBPrivateImpl: CEDAR PROGRAM IMPORTS BasicTime, DB, FileNames, Atom, IO, Rope, TextFind, AlpTransaction EXPORTS WhiteboardDBPrivate = BEGIN OPEN WhiteboardDBPrivate, DBDefs; ROPE: TYPE = Rope.ROPE; WBSegment: PUBLIC ROPE _ NIL; readOnly: PUBLIC BOOL _ TRUE; wbType: PUBLIC ATOM _ $Whiteboard; whiteboardTrans: DBCommon.TransactionHandle; volumeGroupID: AlpTransaction.VolumeGroupID; <> WBEntity: DBDefs.Domain; -- the domain of whiteboards WBTypeProc: PROC[] RETURNS[type: TypeCode] = { type _ DB.TypeForDomain[WBEntity] }; WBType: DB.TypeSpec = [indirect[WBTypeProc]]; <<>> <> versionProp: CARDINAL = 1; gridProp: CARDINAL = 2; createDateProp: CARDINAL = 3; WhiteboardPropFields: DB.FieldSpec = DB.L2FS[LIST[[name: "whiteboard", type: WBType], [name: "version", type: DB.Integer], [name: "grid", type: DB.Integer], [name: "createDate", type: DB.Time]]]; WhiteboardProps: DBDefs.Relation; WBItem: DBDefs.Domain; -- the domain of entities that are displayed on whiteboards Note: DBDefs.Domain; -- notes (text boxes) are a subclass of WBItems Icon: DBDefs.Domain; -- Icons are the other class of WBItems WBItemTypeProc: PROC[] RETURNS[type: TypeCode] = {type _ DB.TypeForDomain[WBItem]}; WBItemType: DB.TypeSpec = [indirect[WBItemTypeProc]]; NoteTypeProc: PROC[] RETURNS[type: TypeCode] = { type _ DB.TypeForDomain[Note] }; NoteType: DB.TypeSpec = [indirect[NoteTypeProc]]; IconTypeProc: PROC[] RETURNS[type: TypeCode] = { type _ DB.TypeForDomain[Icon] }; <<>> IconType: DB.TypeSpec = [indirect[IconTypeProc]]; <> contents: CARDINAL = 1; format: CARDINAL = 2; NotePropFields: DB.FieldSpec = DB.L2FS[LIST[[name: "note", type: NoteType], [name: "contents", type: DB.String, lengthHint: 50], [name: "format", type: DB.String, lengthHint: 50]]]; NoteProps: DBDefs.Relation; <> iconName: CARDINAL = 1; iconLabel: CARDINAL = 2; iconType: CARDINAL = 3; iconIcon: CARDINAL = 4; iconArgument: CARDINAL = 5; IconPropFields: DB.FieldSpec = DB.L2FS[LIST[[name: "icon", type: IconType], [name: "iconName", type: DB.String, lengthHint: 40], [name: "iconLabel", type: DB.String, lengthHint: 40], [name: "iconType", type: DB.String, lengthHint: 20], [name: "iconIcon", type: DB.String, lengthHint: 20], [name: "iconArgument", type: DB.String, lengthHint: 40]]]; IconProps: DBDefs.Relation; <> container: DBDefs.Relation; containerItem: CARDINAL = 0; containerWB: CARDINAL = 1; containerX: CARDINAL = 2; containerY: CARDINAL = 3; containerW: CARDINAL = 4; containerH: CARDINAL = 5; containerPropFields: DB.FieldSpec = DB.L2FS[LIST[[name: "item", type: WBItemType], [name: "of", type: WBType], [name: "x", type: DB.Integer], [name: "y", type: DB.Integer], [name: "w", type: DB.Integer], [name: "h", type: DB.Integer]]]; CloseTransaction: PUBLIC PROC [] = { aborted: BOOL _ FALSE; IF whiteboardTrans = NIL THEN RETURN; DB.CloseTransaction[whiteboardTrans ! DB.Aborted => { aborted _ TRUE; CONTINUE }; DB.Error, DB.Failure => CONTINUE ]; IF aborted THEN DB.AbortTransaction[whiteboardTrans]; whiteboardTrans _ NIL }; OpenTransaction: PUBLIC PROC [] = { schemaInvalid: BOOL; IF whiteboardTrans = NIL THEN { [whiteboardTrans, schemaInvalid] _ DB.OpenTransaction[$Whiteboard]; IF schemaInvalid THEN ResetSchema[] }; volumeGroupID _ AlpTransaction.GetNextVolumeGroup[handle: NARROW[whiteboardTrans.trans]] }; AbortTransaction: PUBLIC PROC [] = { IF whiteboardTrans = NIL THEN RETURN; DB.AbortTransaction[whiteboardTrans ! DB.Error, DB.Failure, DB.Aborted => CONTINUE ]; whiteboardTrans _ NIL }; MarkTransaction: PUBLIC PROC [unlock: BOOL _ TRUE] = { IF whiteboardTrans # NIL THEN { alpTrans: AlpTransaction.Handle = NARROW[whiteboardTrans.trans]; DB.MarkTransaction[whiteboardTrans]; IF unlock THEN AlpTransaction.UnlockOwnerDB[alpTrans, volumeGroupID] } }; Initialize: PUBLIC PROC[DBFile: ROPE] RETURNS[serverDown: BOOL] = BEGIN serverDown _ FALSE; IF NOT Rope.Equal[WBSegment, DBFile, FALSE] THEN { ENABLE DB.Failure => {WBSegment _ NIL; serverDown _ TRUE; CONTINUE}; WBSegment _ DBFile; CloseTransaction[]; SetUpSegment[] }; END; ResetSchema: PROC[] = { Note _ DB.DeclareDomain["Note", $Whiteboard]; Icon _ DB.DeclareDomain["WBIcon", $Whiteboard]; WBItem _ DB.DeclareDomain["WBItems", $Whiteboard]; DB.DeclareSubType[of: WBItem, is: Note]; DB.DeclareSubType[of: WBItem, is: Icon]; WBEntity _ DB.DeclareDomain["Whiteboard", $Whiteboard]; WhiteboardProps _ DB.DeclareProperty[name: "WhiteboardProps", segment: $Whiteboard, fields: WhiteboardPropFields]; NoteProps _ DB.DeclareProperty[name: "NoteProps", segment: $Whiteboard, fields: NotePropFields]; IconProps _ DB.DeclareProperty[name: "IconProps", segment: $Whiteboard, fields: IconPropFields]; container _ DB.DeclareProperty[name: "container", segment: $Whiteboard, fields: containerPropFields] }; SetUpSegment: PROC [] ~ { segmentNumber: NAT = 310B; readOnly _ FALSE; DB.Initialize[nCachePages: 256]; <> DB.DeclareSegment[WBSegment, wbType, segmentNumber]; OpenTransaction[ ! DB.Error => IF code = ProtectionViolation THEN { readOnly _ TRUE; CONTINUE } ELSE REJECT ]; IF readOnly THEN { <> CloseTransaction[]; DB.DeclareSegment[filePath: WBSegment, segment: wbType, number: segmentNumber, readonly: TRUE]; OpenTransaction[] } }; <> DeclareWhiteboard: PUBLIC PROC[name: ROPE] RETURNS[wb: Whiteboard] = { wb _ DB.LookupEntity[WBEntity, name]; IF wb # NIL THEN RETURN; wb _ DB.DeclareEntity[WBEntity, name]; [] _ DB.CreateRelship[WhiteboardProps, DB.L2VS[LIST[DB.E2V[wb], DB.I2V[0], DB.I2V[1], DB.T2V[BasicTime.Now[]]]]] }; GetVersion: PUBLIC PROC[wb: Whiteboard] RETURNS[version: INT] = { version _ DB.V2I[DB.GetP[wb, WhiteboardProps, versionProp]] }; SetVersion: PUBLIC PROC[wb: Whiteboard, version: INT] = { [] _ DB.SetP[wb, WhiteboardProps, versionProp, DB.I2V[version]] }; GetGridSize: PUBLIC PROC[wb: Whiteboard] RETURNS[gridSize: INT] = { gridSize _ DB.V2I[DB.GetP[wb, WhiteboardProps, gridProp]]; IF gridSize <= 0 THEN gridSize _ 1 }; SetGridSize: PUBLIC PROC[wb: Whiteboard, gridSize: INT] = { [] _ DB.SetP[wb, WhiteboardProps, gridProp, DB.I2V[gridSize]] }; GetCreateDate: PUBLIC PROC[wb: Whiteboard] RETURNS[date: BasicTime.GMT] = { date _ DB.V2T[DB.GetP[wb, WhiteboardProps, createDateProp]] }; SetCreateDate: PUBLIC PROC[wb: Whiteboard, date: BasicTime.GMT] = { [] _ DB.SetP[wb, WhiteboardProps, createDateProp, DB.T2V[date]] }; NameOf: PUBLIC PROC[wb: Whiteboard] RETURNS[name: ROPE] = { name _ DB.EntityInfo[wb].name }; DestroyWhiteboard: PUBLIC PROC[wb: Whiteboard] = { IF DB.NullEntity[wb] THEN RETURN; DB.DestroyEntity[wb]; <> FOR wbList: LIST OF Whiteboard _ Enumerate[NIL], wbList.rest UNTIL wbList = NIL DO nextWB: Whiteboard = wbList.first; name: ROPE = NameOf[nextWB]; children: ChildSet = Children[nextWB, TRUE]; FOR child: WhiteboardDBPrivate.WBItem _ NextChild[children], NextChild[children] UNTIL child = NIL DO IF Rope.Equal[name, GetIconProps[child].name] THEN DB.DestroyEntity[child] ENDLOOP ENDLOOP }; Exists: PUBLIC PROC[name: ROPE] RETURNS[BOOL] = { RETURN[NOT DB.NullEntity[DB.LookupEntity[WBEntity, name]]] }; Enumerate: PUBLIC PROC[pattern: ROPE] RETURNS[wbList: LIST OF Whiteboard] = { wbSet: DBDefs.EntitySet = DB.DomainSubset[d: WBEntity, lowName: NIL, highName: NIL, start: First]; BEGIN ENABLE UNWIND => DB.ReleaseEntitySet[wbSet]; finder: TextFind.Finder = IF pattern = NIL THEN NIL ELSE TextFind.CreateFromRope[pattern: pattern, ignoreCase: TRUE, addBounds: TRUE]; FOR wb: DBDefs.Entity _ DB.NextEntity[wbSet], DB.NextEntity[wbSet] UNTIL wb = NIL DO IF finder = NIL OR TextFind.SearchRope[finder, DB.EntityInfo[wb].name].found THEN wbList _ CONS[wb, wbList] ENDLOOP; DB.ReleaseEntitySet[wbSet] END }; <> FetchWBItem: PUBLIC PROC[name: ROPE, type: ItemType] RETURNS[item: WhiteboardDBPrivate.WBItem] = { item _ IF type = note THEN DB.LookupEntity[Note, name] ELSE DB.LookupEntity[Icon, name] }; Parent: PUBLIC PROC[item: WhiteboardDBPrivate.WBItem] RETURNS[wb: Whiteboard] = { wb _ DB.V2E[DB.GetP[e: item, r: container, field: containerWB]] }; Children: PUBLIC PROC[wb: Whiteboard, onlyWhiteboards: BOOL _ FALSE] RETURNS[children: ChildSet] = { rs: DBDefs.RelshipSet = DB.RelshipsWithEntityField[container, containerWB, wb]; children _ NEW[ChildSetObject _ [rs, onlyWhiteboards]] }; NextChild: PUBLIC PROC[children: ChildSet] RETURNS[child: WhiteboardDBPrivate.WBItem] = { rs: DBDefs.RelshipSet = children.rs; IF rs # NIL THEN { IF NOT children.screen THEN { next: DBDefs.Relship = DB.NextRelship[rs]; IF next = NIL THEN RETURN[NIL]; child _ DB.V2E[DB.GetF[next, containerItem]] } ELSE FOR next: DBDefs.Relship _ DB.NextRelship[rs], DB.NextRelship[rs] UNTIL next = NIL DO child _ DB.V2E[DB.GetF[next, containerItem]]; IF TypeOf[child] = icon AND GetIconProps[child].type = wbType THEN EXIT ELSE child _ NIL ENDLOOP; IF child = NIL THEN {DB.ReleaseRelshipSet[rs]; children.rs _ NIL} } ELSE child _ NIL }; TypeOf: PUBLIC PROC[item: WhiteboardDBPrivate.WBItem] RETURNS[type: ItemType] = { DB.ToUnderType[item]; type _ IF DB.DomainEq[DB.EntityInfo[item].domain, Note] THEN note ELSE icon }; Position: PUBLIC PROC[item: WhiteboardDBPrivate.WBItem] RETURNS[x, y: INT] = { cRS: DBDefs.Relship = DB.LookupProperty[container, item]; x _ DB.V2I[DB.GetF[cRS, containerX]]; y _ DB.V2I[DB.GetF[cRS, containerY]] }; Size: PUBLIC PROC[item: WhiteboardDBPrivate.WBItem] RETURNS[w, h: INT] = { cRS: DBDefs.Relship = DB.LookupProperty[container, item]; w _ DB.V2I[DB.GetF[cRS, containerW]]; h _ DB.V2I[DB.GetF[cRS, containerH]] }; Move: PUBLIC PROC[item: WhiteboardDBPrivate.WBItem, newX, newY: INT] = { cRS: DBDefs.Relship = DB.LookupProperty[container, item]; DB.SetF[cRS, containerX, DB.I2V[newX]]; DB.SetF[cRS, containerY, DB.I2V[newY]] }; Destroy: PUBLIC PROC[item: WhiteboardDBPrivate.WBItem] = { IF NOT DB.NullEntity[item] THEN DB.DestroyEntity[item] }; <> MakeRandomName: PROC[] RETURNS[name: Rope.ROPE] = { random: LONG CARDINAL = LOOPHOLE[BasicTime.GetClockPulses[]]; name _ IO.PutR[IO.card[random]] }; NewNote: PUBLIC PROC[parent: Whiteboard, x, y, w, h: INT, content: ViewerTools.TiogaContents] RETURNS[newNote: WBNote] = { note: WBNote = DB.DeclareEntity[d: Note, name: MakeRandomName[]]; props: DBDefs.Relship = DB.CreateRelship[container, DB.L2VS[LIST[DB.E2V[note], DB.E2V[parent], DB.I2V[x], DB.I2V[y], DB.I2V[w], DB.I2V[h]]]]; noteProps: DBDefs.Relship = DB.CreateRelship[NoteProps, DB.L2VS[LIST[DB.E2V[note], DB.S2V[content.contents], DB.S2V[content.formatting]]]]; RETURN[note] }; <<>> GetContents: PUBLIC PROC[note: WBNote] RETURNS[content: ViewerTools.TiogaContents] = { content _ NEW[ViewerTools.TiogaContentsRec _ []]; content.contents _ DB.V2S[DB.GetP[note, NoteProps, contents]]; content.formatting _ DB.V2S[DB.GetP[note, NoteProps, format]] }; <<>> SetContents: PUBLIC PROC[note: WBNote, content: ViewerTools.TiogaContents] = { DB.SetP[note, NoteProps, contents, DB.S2V[content.contents]]; DB.SetP[note, NoteProps, format, DB.S2V[content.formatting]] }; <<>> Grow: PUBLIC PROC[note: WBNote, newW, newH: INT] = { DB.SetP[note, container, containerW, DB.I2V[newW]]; DB.SetP[note, container, containerH, DB.I2V[newH]] }; <> NewIcon: PUBLIC PROC[parent: Whiteboard, x, y: INT, name, label, icon, argument: ROPE, type: ATOM] RETURNS[newIcon: WBIcon] = { wbIcon: WhiteboardDBPrivate.WBIcon = DB.DeclareEntity[d: Icon, name: MakeRandomName[]]; props: DBDefs.Relship = DB.CreateRelship[container, DB.L2VS[LIST[DB.E2V[wbIcon], DB.E2V[parent], DB.I2V[x], DB.I2V[y], DB.I2V[64], DB.I2V[64]]]]; iconProps: DBDefs.Relship = DB.CreateRelship[IconProps, DB.L2VS[LIST[DB.E2V[wbIcon], DB.S2V[name], DB.S2V[label], DB.S2V[Atom.GetPName[type]], DB.S2V[icon], DB.S2V[argument]]]]; RETURN[wbIcon] }; GetDisplayProps: PUBLIC PROC[wbIcon: WBIcon] RETURNS[label, icon: ROPE] = { label _ DB.V2S[DB.GetP[wbIcon, IconProps, iconLabel]]; icon _ DB.V2S[DB.GetP[wbIcon, IconProps, iconIcon]]; IF Rope.Equal[icon, ""] THEN { icon _ DefaultIcon[wbIcon]; DB.SetP[wbIcon, IconProps, iconIcon, DB.S2V[icon]] }; IF Rope.Equal[label, ""] THEN { type: ATOM; name: ROPE; [name, type] _ GetIconProps[wbIcon]; label _ IF type = $Text THEN FileNames.GetShortName[name] ELSE name; IF NOT readOnly THEN DB.SetP[wbIcon, IconProps, iconLabel, DB.S2V[label]] } }; GetToolArgument: PUBLIC PROC[wbIcon: WBIcon] RETURNS[argument: ROPE] = { argument _ DB.V2S[DB.GetP[wbIcon, IconProps, iconArgument]] }; DefaultIcon: PROC[wbIcon: WBIcon] RETURNS[iconName: ROPE] = { name: ROPE; type: ATOM; [name, type] _ GetIconProps[wbIcon]; SELECT type FROM wbType => iconName _ "Whiteboard"; $ToolRope => iconName _ "Typescript"; $Text => iconName _ "Document"; $Tool => iconName _ name; ENDCASE => iconName _ "Acorn" }; GetIconProps: PUBLIC PROC[wbIcon: WBIcon] RETURNS[name: ROPE, type: ATOM] = { name _ DB.V2S[DB.GetP[wbIcon, IconProps, iconName]]; type _ Atom.MakeAtom[DB.V2S[DB.GetP[wbIcon, IconProps, iconType]]] }; SetProps: PUBLIC PROC[wbIcon: WBIcon, name, label, icon: ROPE, type: ATOM] = { [] _ DB.SetP[wbIcon, IconProps, iconIcon, DB.S2V[icon]]; [] _ DB.SetP[wbIcon, IconProps, iconName, DB.S2V[name]]; [] _ DB.SetP[wbIcon, IconProps, iconLabel, DB.S2V[IF label = NIL THEN name ELSE label]]; [] _ DB.SetP[wbIcon, IconProps, iconType, DB.S2V[Atom.GetPName[type]]]}; END...