-- creating the calendar form on the display and registering actions that are implemented by
-- CalFormImplB.mesa. Also dealing with resetting and erasing the form, once it was created.
DIRECTORY
BasicTime USING [ Unpack, Now, GMT, nullGMT, earliestGMT, latestGMT],
Buttons USING [ Button, ReLabel],
Calendar USING [ Date, Years, Months, Days, Weekdays],
CalEnter USING [ EnterEvents],
CalForm USING [ RepetitionDescriptor, FormWidth, Delta, FormHeight, YearTable, MonthTable, DayTable, Row1, Row234, Row5, Row6, Row7, MenuTable, CalForm, CurSelection, TranslateSelection, SyntaxError, CreateCalFormCont, FillDayTable, ExtractTimeSpec],
CalNuts USING [ ResetNutInfo],
CalStorage USING [ protData, Mode],
CalSupport USING [ MakeMenu, GetMonthInfo, M2I, R2I, GetRowCol, ExtractDate, ClearButton, SetButton, GetIconFlavor],
Containers USING [ Container],
Hickory USING [ RepetitionType, ListGroups, ProtectionType, GroupSet, Event, EventTuple, EventList, SameEvent, Reason, RestoreEvents],
Labels USING [ Set, Label],
Menus USING [ MenuProc],
Rope USING [ ROPE],
RopeSets USING [ RopeSetEl, IsValueInSet, InsertValueIntoSet, DeleteValueFromSet, Difference, Union, RopeSet],
Tempus USING [ MakeRope],
ViewerClasses USING [ Viewer, ViewerRec],
ViewerOps USING [ PaintViewer, MoveViewer, SetMenu, DestroyViewer],
ViewerTools USING [ SetContents],
VTables USING [ VTable, GetTableEntry]
;
CalFormImpl:
CEDAR
MONITOR
LOCKS CalStorage.protData
IMPORTS BasicTime, CalStorage, CalSupport, Hickory, ViewerOps, CalForm, RopeSets, Tempus, ViewerTools, Buttons, CalEnter, Labels, VTables, CalNuts
EXPORTS CalForm
SHARES CalSupport, CalForm, CalEnter, CalNuts
Utility Operations
DestroyViewer:
PUBLIC
INTERNAL
PROC =
BEGIN
is called when calViewer was destroyed... Must set all ptr to NIL so GC gets the garbage
IF calForm.container #
NIL
THEN
BEGIN
ViewerOps.DestroyViewer[ calForm.container];
calForm.container ← NIL;
END;
curSelection ← SetSelection[];
editedEv ← NIL;
BEGIN
OPEN calForm.row1;
yearTable.table ← NIL;
FOR i: INT IN [ 1..yearTable.cols] DO yearTable.buttons[ i] ← NIL; ENDLOOP;
monthTable.table ← NIL;
FOR i: INT IN [ 1..monthTable.cols] DO yearTable.buttons[ i] ← NIL; ENDLOOP;
dayTable.table ← NIL;
FOR l:
INT
IN [ 0.. dayTable.cols-1]
DO
FOR i:
INT
IN [ 0.. dayTable.rows-2]
DO
-- title row
dayTable.buttons[ i] [ l] ← NIL;
ENDLOOP;
ENDLOOP;
END; -- row1
calForm.row2.table ← NIL; calForm.row2.txtViewer ← NIL;
calForm.row3.table ← NIL; calForm.row3.txtViewer ← NIL;
calForm.row4.table ← NIL; calForm.row4.txtViewer ← NIL;
calForm.row5.table ← NIL; calForm.row5.txtViewer ← NIL;
BEGIN
OPEN calForm.row5.menuTable;
table ← NIL;
FOR i: INT IN [ 0..cols-1) DO buttons [i] ← NIL; ENDLOOP;
END;
calForm.row6.table ← NIL; calForm.row6.txtViewer ← NIL;
calForm.row6.groups ← [ NIL, NIL]; calForm.row6.groupHead ← NIL;
BEGIN
OPEN calForm.row6.menuTable;
table ← NIL;
FOR i: INT IN [ 0..cols-1) DO buttons [i] ← NIL; ENDLOOP;
END;
calForm.row7.table ← NIL;
calForm.row7.txtViewers[ 1] ← NIL; calForm.row7.txtViewers[ 2] ← NIL;
calForm.row8.table ← NIL;
END; -- DestroyViewer
SetSelection:
PROCEDURE [ ev:
REF Hickory.EventTuple ←
NIL, gr: Hickory.GroupSet ← [
NIL,
NIL]]
RETURNS [ sel: CurSelection] =
BEGIN
to set the selection and also protData.curDate
BEGIN
OPEN sel;
IF ev #
NIL
THEN
BEGIN
date ← CalSupport.ExtractDate[ ev.EventTime];
curDate ← date;
repetition.RepeatType ← ev.RepeatType;
repetition.RepeatTime ← ev.RepeatTime;
repetition.RepeatUntil ← ev.RepeatUntil;
groups ← gr;
protection ← ev.Protection;
reminder ← ev.Remind;
END
ELSE
BEGIN
date ← CalSupport.ExtractDate[ BasicTime.Now[]];
curDate ← date;
repetition.RepeatType ← None;
repetition.RepeatUntil ← BasicTime.nullGMT;
repetition.RepeatTime ← NIL;
protection ← Private;
reminder ← TRUE;
groups ← gr;
END;
END; -- OPEN
RETURN[ sel];
END; -- SetSelection
GetFirstOccurrence:
PROCEDURE [ key: Hickory.Event]
RETURNS [ tuple:
REF Hickory.EventTuple] =
BEGIN
when we are editing a repeated event, make sure we are editing the first occurrence of it
otherwise confusion results at later stages. Note that this is a somewhat arbitrary
semantics..
evl: Hickory.EventList;
evl ← Hickory.RestoreEvents[ from: BasicTime.earliestGMT, to: BasicTime.latestGMT, key: key];
IF evl.rest # NIL THEN ERROR
ELSE tuple ← NEW[ Hickory.EventTuple ← evl.first];
RETURN[ tuple];
END; -- GetFirstOccurrence
Building the form on the screen...
CreateCalForm:
PUBLIC
INTERNAL
PROC [ mode: CalStorage.Mode, ev:
REF Hickory.EventTuple ←
NIL] =
BEGIN
here we start our effort to build the form on the screen. IF ev = NIL we start with new
event, else we are editing one.
oldSelection: CurSelection ← curSelection;
iconFile: Rope.ROPE ← "Calendar.icons";
curMode ← mode;
CalNuts.ResetNutInfo[ mode: EnterEvent];
calViewer.icon ← CalSupport.GetIconFlavor[ EnterEvent];
IF ev =
NIL
AND editedEv #
NIL
THEN
BEGIN
curSelection ← SetSelection[];
editedEv ← NIL;
END
ELSE
IF ev #
NIL
THEN
BEGIN
-- editing an existing event
IF ev.RepeatType # None THEN ev ← GetFirstOccurrence[ ev.Key];
curSelection ← SetSelection[ ev, Hickory.ListGroups[ ev.Key]];
editedEv ← ev;
END;
AdjustCaption[ calViewer];
ViewerOps.SetMenu[ viewer: calViewer, menu: CalSupport.MakeMenu[ LIST[ "DoIt", "Erase", "Reset"], LIST[ DoIt, Erase, Reset], LIST[ NIL, NIL, NIL]], paint: FALSE];
DrawCalForm[ calViewer, editedEv, oldSelection];
END;
AdjustCaption:
INTERNAL
PROCEDURE [ viewer: ViewerClasses.Viewer] =
BEGIN
here we change the title of the viewer a bit
IF curMode = EnterEvent THEN viewer.name ← "Calendar: entering/editing event"
ELSE viewer.name ← "Calendar: querying data base";
END; -- AdjustCaption
DrawCalForm:
INTERNAL
PROCEDURE [ myParent: ViewerClasses.Viewer, ev: REF Hickory.EventTuple, oldSelection: CurSelection] =
BEGIN
here we draw the form on the screen. Either we build it from scratch or we fill in
the viewers that are already existing.
IF calForm.container = NIL THEN CreateCalFormCont[ myParent, ev]
ELSE
BEGIN
UpdateDateTables[ oldSelection.date, curSelection.date];
UpdateProtectionButton[ oldSelection.protection, curSelection.protection];
UpdateReminderButton[ oldSelection.reminder, curSelection.reminder];
IF ev #
NIL
THEN
BEGIN
-- editing an existing event
EraseForm[ oldSelection, FALSE];
RefillForm[ ev, curSelection];
END
ELSE EraseForm[ oldSelection, TRUE];
ViewerOps.MoveViewer[ viewer: calForm.container, x: calForm.container.wx-Delta, y: calForm.container.wy-Delta, w: calForm.container.ww, h: calForm.container.wh, paint: TRUE];
END;
Menu Procedures
Reset: Menus.MenuProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: MouseButton ← red, shift, control: BOOL ← FALSE] -- =
BEGIN
DoCmd[ Reset];
END;
Erase: Menus.MenuProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: MouseButton ← red, shift, control: BOOL ← FALSE] -- =
BEGIN
DoCmd[ Erase];
END;
DoIt: Menus.MenuProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: MouseButton ← red, shift, control: BOOL ← FALSE] -- =
BEGIN
DoCmd[ DoIt];
END;
DoCmd:
ENTRY
PROCEDURE [ cmd: Commands] =
BEGIN
ENABLE UNWIND => NULL;
SELECT cmd
FROM
Reset => ResetForm[ Reset];
Erase => ResetForm[ Erase];
DoIt => TranslateAndEnter[];
ENDCASE;
END; -- DoCmd
TranslateAndEnter:
INTERNAL
PROCEDURE =
BEGIN
to translate the form and enter it into hickory...
groups: Hickory.GroupSet ← [ NIL, NIL];
evl: Hickory.EventList;
ok: BOOLEAN ← TRUE;
[ evl, groups] ← TranslateSelection[ editedEv ! SyntaxError => { ok ← FALSE; CONTINUE }];
IF ok
THEN
BEGIN
CalEnter.EnterEvents[ editedEv, evl, groups];
END;
END; -- TranslateAndEnter
ResetForm:
INTERNAL
PROCEDURE [ cmd: Commands] =
BEGIN
to reset current selection and clear form if cmd = Erase. If reset and we are editing
an existing event, reinitialize form.
oldSelection: CurSelection ← curSelection;
IF cmd = Erase
OR editedEv =
NIL
THEN
BEGIN
EraseForm[ curSelection, TRUE];
curSelection ← SetSelection[];
END
ELSE
BEGIN
-- Reset to edited ev
EraseForm[ curSelection, FALSE];
curSelection ← SetSelection[ editedEv, Hickory.ListGroups[ editedEv^.Key]];
RefillForm[ editedEv, curSelection];
END;
UpdateDateTables[ oldSelection.date, curSelection.date];
UpdateProtectionButton[ oldSelection.protection, curSelection.protection];
UpdateReminderButton[oldSelection.reminder, curSelection.reminder];
END; -- ResetForm
EraseForm:
INTERNAL
PROCEDURE [ selection: CurSelection, all:
BOOLEAN ←
TRUE] =
BEGIN
to undo the current contents.
OPEN calForm;
IF all
THEN
BEGIN
ViewerTools.SetContents[ row2.txtViewer, "", TRUE];
ViewerTools.SetContents[ row3.txtViewer, "", TRUE];
ViewerTools.SetContents[ row4.txtViewer, "", TRUE];
ViewerTools.SetContents[ row5.txtViewer, "", TRUE];
ViewerTools.SetContents[ row6.txtViewer, "", TRUE];
ViewerTools.SetContents[ row7.txtViewers[1], "", TRUE];
ViewerTools.SetContents[ row7.txtViewers[2], "", TRUE];
END;
EraseRepetitionSelection[ selection.repetition.RepeatType];
EraseSelectedGroups[];
END; -- EraseForm
EraseRepetitionSelection:
INTERNAL
PROC [ repType: Hickory.RepetitionType] =
BEGIN
OPEN calForm.row5;
IF repType
IN [ Hourly..Yearly]
THEN
CalSupport.ClearButton[menuTable.buttons[ CalSupport.R2I[ repType]-1]];
END; -- EraseRepetitionSelection
EraseSelectedGroups:
INTERNAL
PROCEDURE =
BEGIN
to graphically erase selected groups...
OPEN calForm.row6;
FOR i:
INT
IN [ 0..menuTable.cols)
DO
CalSupport.ClearButton[menuTable.buttons[ i]];
ENDLOOP;
END; -- EraseSelectedGroups
RefillForm:
INTERNAL
PROCEDURE [ evPtr:
REF Hickory.EventTuple, curSelection: CurSelection] =
BEGIN
to refill the form without drawing it from scratch.
OPEN calForm;
tr: Rope.ROPE;
ev: Hickory.EventTuple;
IF evPtr = NIL THEN RETURN;
ev ← evPtr^;
tr ← ExtractTimeSpec[ ev.EventTime, ev.Duration];
ViewerTools.SetContents[ row2.txtViewer, tr, TRUE];
ViewerTools.SetContents[ row3.txtViewer, ev.Text, TRUE];
ViewerTools.SetContents[ row4.txtViewer, ev.Place, TRUE];
ViewerTools.SetContents[ row5.txtViewer, ev.RepeatTime, TRUE];
RefillRepeatMenu[ ev.RepeatType];
RefillGroupMenu[];
IF ev.RepeatUntil # BasicTime.nullGMT
THEN
ViewerTools.SetContents[ row7.txtViewers[1], Tempus.MakeRope[ time: ev.RepeatUntil], TRUE]
ELSE ViewerTools.SetContents[ row7.txtViewers[1], "", TRUE];
IF ev.KeepUntil # BasicTime.nullGMT
THEN
ViewerTools.SetContents[ row7.txtViewers[2], Tempus.MakeRope[ time: ev.KeepUntil], TRUE]
ELSE ViewerTools.SetContents[ row7.txtViewers[2], "", TRUE];
END; -- RefillForm
UpdateDateTables:
INTERNAL
PROCEDURE [ oldDate, newDate: Date] =
BEGIN
to update the year, month and day tables
OPEN calForm.row1;
oldRow, newRow, oldCol, newCol: CARDINAL;
IF oldDate = newDate THEN RETURN;
IF oldDate.Year # newDate.Year
THEN
BEGIN
OPEN yearTable;
oldRow ← oldDate.Year - curYear + ( rows-1)/2;
newRow ← newDate.Year - curYear + ( rows-1)/2;
CalSupport.ClearButton[ buttons[ oldRow]];
CalSupport.SetButton[ buttons[ newRow]];
END; -- yearTable
IF oldDate.Month # newDate.Month
THEN
BEGIN
OPEN monthTable;
oldRow ← CalSupport.M2I[ oldDate.Month] + 1;
newRow ← CalSupport.M2I[ newDate.Month] + 1;
CalSupport.ClearButton[ buttons[ oldRow]];
CalSupport.SetButton[ buttons[ newRow]];
END; -- monthTable
IF oldDate.Month # newDate.Month
OR oldDate.Year # newDate.Year
THEN
BEGIN
FillDayTable[ dayTable.table, newDate];
ViewerOps.PaintViewer[ dayTable.table, all];
END
ELSE
IF oldDate.Day # newDate.Day
THEN
BEGIN
-- only need to change two buttons
OPEN dayTable;
firstDay: Weekdays;
nbrOfDays: Days;
[ nbrOfDays, firstDay] ← CalSupport.GetMonthInfo[ oldDate.Month, oldDate.Year];
[ oldRow, oldCol] ← CalSupport.GetRowCol[ oldDate.Day, firstDay];
[ newRow, newCol] ← CalSupport.GetRowCol[ newDate.Day, firstDay];
CalSupport.ClearButton[ buttons[ oldRow] [ oldCol]];
CalSupport.SetButton[ buttons[ newRow] [ newCol]];
END; -- daytable
UpdateProtectionButton:
INTERNAL
PROC [ oldProt, newProt: Hickory.ProtectionType] =
BEGIN
OPEN calForm.row8;
label: Labels.Label;
IF oldProt = newProt THEN RETURN;
label ← VTables.GetTableEntry[ table: calForm.row8.table, row: 0, column: 1];
IF newProt = Private THEN Labels.Set[ label, " Private"]
ELSE Labels.Set[ label, " Private"];
END; -- UpdateProtectionButton
UpdateReminderButton:
INTERNAL
PROC [ oldRem, newRem: BOOLEAN] =
BEGIN
OPEN calForm.row8;
label: Labels.Label;
IF oldRem = newRem THEN RETURN;
label ← VTables.GetTableEntry[ table: calForm.row8.table, row: 0, column: 3];
IF newRem THEN Labels.Set[ label, " Yes"]
ELSE Labels.Set[ label, " No"];
END; -- UpdateReminderButton
RefillRepeatMenu:
INTERNAL
PROCEDURE [ repType: Hickory.RepetitionType] =
BEGIN
to adjust the repetiton menu when we are editing an old event.
IF repType IN [ Hourly..Yearly]
THEN
CalSupport.SetButton[ calForm.row5.menuTable.buttons[ CalSupport.R2I[ repType]-1]];
END; -- RefillRepeatMenu
RefillGroupMenu:
INTERNAL
PROCEDURE =
BEGIN
to refill the group menu. Assume that calForm.row6.groups knows about all
the groups in hickory. curSelection contains groups currently selected groups.
OPEN calForm.row6;
gr: REF RopeSets.RopeSetEl;
IF calForm.container = NIL OR calForm.container.destroyed THEN RETURN;
IF txtViewer = NIL THEN RETURN; -- row6 not initialized
ViewerTools.SetContents[ txtViewer, "", TRUE]; -- all known hickory groups are in menu
groupHead ← groups.Head;
gr ← groupHead;
FOR i:
INT
IN [ 0..menuTable.cols)
DO
IF gr #
NIL
THEN
BEGIN
Buttons.ReLabel[ menuTable.buttons[ i], gr.Value, FALSE];
IF RopeSets.IsValueInSet[ gr.Value, curSelection.groups]
THEN
CalSupport.SetButton[ menuTable.buttons[ i]]
ELSE CalSupport.ClearButton[ menuTable.buttons[ i]];
gr ← gr.Next;
END
ELSE
BEGIN
Buttons.ReLabel[ menuTable.buttons[ i], "", FALSE]; -- erase
CalSupport.ClearButton[ menuTable.buttons[ i]];
END;
ENDLOOP;
END; -- RefillGroupMenu