-- File NoteEditorImpl.mesa
-- Created by Donahue, October 27, 1982 11:37 am
-- Last edited by:
-- Donahue March 14, 1983 3:35 pm
-- Cattell December 22, 1983 12:57 pm

DIRECTORY
Buttons: TYPE USING[ ButtonProc ],
DB,
DBEnvironment,
NoteEditor,
Menus,
Rope,
VFonts,
ViewerClasses: TYPE USING[ Viewer ],
ViewerOps: TYPE USING[ AddProp, FetchProp, PaintHint, PaintViewer ],
ViewerTools,
VTables: TYPE USING[ VTable, Create, GetTableEntry, GetEntryOffset,
       NullBorder, SetTableEntry, Install, SetEntryOffset ];

NoteEditorImpl: PROGRAM
IMPORTS DB, ViewerOps, VTables, Rope, VFonts, ViewerTools
EXPORTS NoteEditor =

BEGIN OPEN DB, Rope, ViewerClasses, VTables;

DisplayNote: PUBLIC PROC[ entity: Entity,
         parent: Viewer,
         segment: DB.Segment ← NIL,
         openHeight: NAT ← 0,
         openWidth: NAT ← 0, noEdits: BOOLEANFALSE ]
     RETURNS[ NoteRow: VTable] = {
-- Display note subwindow. Note that if noEdits=TRUE and the required schema is underfined
-- or no note exists, then we return immediately.
NoteRel: Relation =
 DeclareRelation["note", IF entity = NIL THEN segment ELSE SegmentOf[entity], OldOnly];
NoteOfAttr: Attribute = DB.DeclareAttribute[
r: NoteRel, name: "of", type: AnyDomainType, version: OldOnly ];
NoteIsAttr: Attribute = DB.DeclareAttribute[
r: NoteRel, name: "is", type: RopeType, version: OldOnly];
noteRelship: Relship← IF NoteRel=NIL OR entity = NIL THEN NIL ELSE
  NextRelship[RelationSubset[NoteRel, LIST[AttributeValue[NoteOfAttr, entity]]]];
text: ROPEIF noteRelship = NIL THEN NIL ELSE GetFS[ noteRelship, NoteIsAttr ];
tiogaText: ViewerTools.TiogaContents← RopeToTioga[text];
IF noEdits AND Rope.Equal[text, ""] THEN RETURN[NIL];
NoteRow ← Create[ columns: 2, parent: parent ];
SetTableEntry[table: NoteRow, column: 0, name: "Notes", flavor: $Button,
     proc: SetHeight, border: NullBorder ];
GetTableEntry[ NoteRow, 0, 0 ].border ← TRUE;
IF openHeight = 0 THEN openHeight ← VFonts.FontHeight[]*(Rope.Length[text]/70+2);
IF openWidth = 0 THEN openWidth ← 40*VFonts.CharWidth['A];
SetTableEntry[ table: NoteRow, column: 1, flavor: $Text, border: NullBorder,
     h: openHeight, w: openWidth, useMaxSize: TRUE ];
GetTableEntry[ NoteRow, 0, 1 ].scrollable ← TRUE;
ViewerTools.SetTiogaContents[
viewer: GetTableEntry[ NoteRow, 0, 1], contents: tiogaText, paint: FALSE ];
IF noEdits THEN
 { ViewerTools.InhibitUserEdits[ GetTableEntry[ NoteRow, 0, 1] ];
  ViewerOps.AddProp[ NoteRow, $edits, NEW[ BOOLEANFALSE ] ] };
Install[ NoteRow, FALSE ];
ViewerOps.AddProp[ NoteRow, $note, noteRelship ] };

SetHeight: Buttons.ButtonProc = TRUSTED {
viewer: Viewer = NARROW[ parent, Viewer ];
NoteRow: VTable = viewer.parent;
textViewer: Viewer = GetTableEntry[ table: NoteRow, column: 1 ];
text: ROPE = ViewerTools.GetContents[ textViewer ];
edits: REF ANY = ViewerOps.FetchProp[ NoteRow, $edits ];
  textHeight: INT = textViewer.wh;
  textWidth: INT = textViewer.ww;
SELECT mouseButton FROM
Menus.MouseButton[red] =>
{ ViewerTools.SetSelection[ viewer: GetTableEntry[ table: NoteRow, column: 1 ],
            selection: NIL ]; RETURN };
   Menus.MouseButton[blue] =>
SetTableEntry[ table: NoteRow, column: 1, flavor: $Text, border: NullBorder,
     useMaxSize: TRUE, w: textWidth,
     h: textHeight+2*VFonts.FontHeight[]+5 ];
ENDCASE;
GetTableEntry[ table: NoteRow, column: 1 ].scrollable ← TRUE;
IF edits # NIL THEN
ViewerTools.InhibitUserEdits[ GetTableEntry[ table: NoteRow, column: 1 ] ];
ViewerTools.SetContents[ viewer: GetTableEntry[ table: NoteRow, column: 1 ],
        contents: text, paint: FALSE ];
Install[ NoteRow, FALSE ];
SetEntryOffset[
table: NoteRow, column: 0, yoff: GetEntryOffset[ table: NoteRow, column: 1 ].yoff ];
  Install[ NoteRow.parent, FALSE ];
ViewerOps.PaintViewer[ NoteRow.parent.parent, ViewerOps.PaintHint[client] ] };

SaveNote: PUBLIC PROC[newEntity: Entity, viewer: Viewer, update: BOOLEANFALSE] = {
text: ROPE = TiogaToRope[ViewerTools.GetTiogaContents[ GetTableEntry[viewer, 0, 1] ]];
NoteRel: Relation = DeclareRelation["note", SegmentOf[newEntity], NewOrOld];
NoteOfAttr: Attribute = DeclareAttribute[NoteRel, "of", AnyDomainType];
NoteIsAttr: Attribute = DeclareAttribute[NoteRel, "is", RopeType];
IF update THEN {
  noteRelship: Relship = V2E[ ViewerOps.FetchProp[ viewer, $note ] ];
IF noteRelship # NIL THEN
  { SetF[ noteRelship, NoteIsAttr, S2V[text] ]; RETURN };
  };
  ViewerOps.AddProp[ viewer, $note, CreateRelship[ r: NoteRel, init: LIST[
  AttributeValue[attribute: NoteOfAttr, lo: newEntity ],
  AttributeValue[attribute: NoteIsAttr, lo: S2V[text]]]]];
  };

TiogaToRope: PROC[tioga: ViewerTools.TiogaContents] RETURNS [rope: ROPE] = {
-- Converts a tioga node into a single rope that can be stored in a database or file.
IF tioga.formatting.Length[]=0 THEN -- No formatting
RETURN[tioga.contents]
ELSE -- Concatenate text and formatting with a null as separator
RETURN[Rope.Cat[tioga.contents, "\000", tioga.formatting]];
};

RopeToTioga: PROC[rope: ROPE] RETURNS [tioga: ViewerTools.TiogaContents] = {
-- Converts a rope into the two parts previously concatenated by TiogaToRope.
pos: INT← rope.Find["\000"];
IF
pos=-1 THEN -- No formatting: fake a Tioga node
tioga← NEW[ViewerTools.TiogaContentsRec[rope, NIL]]
ELSE -- Break into parts before and after null separator
tioga← NEW[ViewerTools.TiogaContentsRec[rope.Substr[0, pos], rope.Substr[pos+1]]];
};

END.