constant kAppSymbol := '|Checkbook:PIETraining|; constant kAppObject := '["Check", "Checks"]; constant kSoupName := "Checkbook:PIETraining"; constant kCheckFormatSymbol := '|CheckFormat:Checkbook:PIETraining|; constant kSoupIndexes := '[ {structure: slot, path: date, type: int}, {structure: slot, path:number, type: int}, ]; constant kAppName := "Checkbook"; constant kMaxApplicationWidth := 800; constant kMaxApplicationHeight := 1600; DefConst('kMinutesPerDay, 24 * 60); InstallScript := func(packageFrame) begin // to set up routing routing.(kAppSymbol) := packageFrame.theForm.routingFrame; GetRoot().(kCheckFormatSymbol) := BuildContext(packageFrame.theForm.printFormat); // To be notified of changes to the soup (including a changed folder) AddArraySlot(soupNotify, kSoupName); AddArraySlot(soupNotify, kAppSymbol); // for Find All AddArraySlot(findApps, kAppSymbol); // for IA packageFrame.taskTemplateID := RegTaskTemplate(packageFrame.theForm.taskTemplate); end; RemoveScript := func(packageFrame) begin // remove routing RemoveSlot(routing, kAppSymbol); RemoveSlot(GetRoot(), kCheckFormatSymbol); // remove soup name and app symbol from soupNotify array local soupNotifyPos := ArrayPos(soupNotify, kAppSymbol, 0, nil); ArrayRemoveCount(soupNotify, soupNotifyPos - 1, 2); // for Find All SetRemove(findApps, kAppSymbol); // for IA if packageFrame.taskTemplateID then begin UnRegTaskTemplate(packageFrame.taskTemplateID); packageFrame.taskTemplateID := nil; end; end; // ---- End Project Data ---- // ---- Beginning of Print templates ---- // ---- File checkFormat ---- printFormat_checkFormat := { printNextPageScript: func() begin return nil; // we only print one page end, _proto: protoPrintFormat, debug: "printFormat_checkFormat" }; checkView := /* child of printFormat_checkFormat */ {viewFlags: 1, viewFormat: 336, viewBounds: {top: 80, left: 4, right: -4, bottom: 230}, viewJustify: 48, DisplayCheck: func(check) begin //displays a check in the checkView SetValue(ckDate, 'text, ShortDateStr(check.date, 0)); SetValue(ckNumber, 'text, NumberStr(check.number)); SetValue(ckPayee, 'text, check.payee); SetValue(ckAmount, 'text, FormattedNumberStr((check.amount), "%0.2f")); SetValue(ckMemo, 'text, check.memo); end;, viewSetupDoneScript: func() begin :DisplayCheck(fields.target); end, viewclass: 74, debug: "checkView" }; ckNumber := /* child of checkView */ {viewBounds: {top: 10, left: -60, right: -2, bottom: 35}, viewJustify: 8388640, viewFlags: 10753, _proto: protoInputLine, debug: "ckNumber" }; // View ckNumber is declared to checkView ckDate := /* child of checkView */ {viewBounds: {top: 0, left: -90, right: -2, bottom: 30}, viewJustify: 8396832, viewFlags: 67648033, _proto: protoInputLine, debug: "ckDate" }; // View ckDate is declared to checkView ckAmount := /* child of checkView */ {viewBounds: {top: 0, left: 12, right: -97, bottom: 0}, viewJustify: 8400944, viewFlags: 10753, _proto: protoInputLine, debug: "ckAmount" }; // View ckAmount is declared to checkView amountLabel := /* child of checkView */ {text: "$", viewBounds: {top: 0, left: -10, right: 0, bottom: 0}, viewJustify: 8402948, _proto: protoStaticText, debug: "amountLabel" }; ckPayee := /* child of checkView */ {viewBounds: {top: 10, left: 2, right: -2, bottom: 40}, viewJustify: 8396848, viewFlags: 14849, _proto: protoInputLine, debug: "ckPayee" }; // View ckPayee is declared to checkView payeeLabel := /* child of checkView */ {text: "Payee", viewBounds: {top: -10, left: 0, right: 50, bottom: 15}, viewJustify: 8398848 , _proto: protoStaticText, debug: "payeeLabel" }; ckMemo := /* child of checkView */ {viewBounds: {top: 0, left: 2, right: -120, bottom: 25}, viewJustify: 8396848, viewFlags: 14849, _proto: protoInputLine, debug: "ckMemo" }; // View ckMemo is declared to checkView memoLabel := /* child of checkView */ {text: "Memo", viewBounds: {top: -5, left: 0, right: 50, bottom: 10}, viewJustify: 8398848, _proto: protoStaticText, debug: "memoLabel" }; name := /* child of checkView */ {text: "Static Text", viewBounds: {left: 5, top: 2, right: 120, bottom: 14}, viewSetupFormScript: func() begin self.text := GetGlobals().userConfiguration.name; end, _proto: protoStaticText, debug: "name" }; address := /* child of checkView */ {text: "Static Text", viewBounds: {left: 0, top: 0, right: 0, bottom: 12}, viewJustify: 8398336, viewSetupFormScript: func() begin self.text := GetGlobals().userConfiguration.address; end, _proto: protoStaticText, debug: "address" }; cityState := /* child of checkView */ {text: "Static Text", viewBounds: {left: 0, top: 0, right: 0, bottom: 12}, viewJustify: 8398336, viewSetupFormScript: func() begin self.text := GetGlobals().userConfiguration.cityZip; end, _proto: protoStaticText, debug: "cityState" }; // ---- End of Print templates ---- // ---- File mainlayout.t ---- // Before Script for "checkBook" // Copyright © 1993, 1994 by Apple Computer, Inc. All rights reserved. nil checkBook := { PutAway: func(item) begin // called by beaming to put beamed frame away in the soup local newEntry := item.body; local theSoup := nil; CheckThatFolderExists(newEntry); if checkbookSoup then theSoup := checkbookSoup else begin theSoup := :RegisterCardSoup(kSoupName, kSoupIndexes, kAppSymbol, kAppObject); :AddNCKSupportIfNecessary(); end; try theSoup:AddToDefaultStore(newEntry); onexception |evt.ex| do begin if not checkbookSoup then :UnRegisterCardSoup(kSoupName); Rethrow(); end; if not checkbookSoup then :UnRegisterCardSoup(kSoupName); BroadcastSoupChange(kSoupName); end, DisplayOverview: func() begin if currentView = checkView then checkView:Hide(); if call kViewIsOpenFunc with (overview) then begin // fill in new data before displaying to avoid ugly redraw. overview:DisplayFromCursor(); overview:Show(); end else overview:Open(); end, taskTemplate: // used by IA. See InstallScript in Project Data DefConst('kPayAction, { name: "pay action", isa: 'dyna_user_action, lexicon: ["pay", "write check"], } ); { value: "pay task", isa: 'task_template, primary_act: kPayAction, preconditions: ['action, 'who, 'whichCompany, 'when, 'amount], signature: [kPayAction, 'person, 'company, 'date, 'number], // The post parse method is called as a method of the taskTemplate // It calls an application method with the taskTemplate as a parameter. postParse: func() GetRoot().(kAppSymbol):PostParseCommand(self), }, AddNCKSupportIfNecessary: func() begin local soup := GetStores()[0]:GetSoup("Directory"); local q := Query(soup, {type: 'index, indexPath: 'soup, startKey: kSoupName, endTest: func(item) NOT StrEqual(item.soup, kSoupName)}); // if upgrading is important, should check version number if not q:Entry() then begin local nckMeta := Clone(nckMetaData); nckMeta.soup := kSoupName; nckMeta.name := kAppName; soup:Add(nckMeta); end; end, viewSetupDoneScript: func() begin if openToOverview then :DisplayOverview(); else :DisplayCurrentCheck(); end, GetCheckAsText: func(check) begin ShortDateStr(check.date, 0) && check.payee && FormattedNumberStr(check.amount, "%0.2f") end, viewFormat: 590161, UndoDuplicateCheck: func(duplicatedCheck) begin EntryRemoveFromSoup(duplicatedCheck); BroadcastSoupChange(kSoupName); // soupChanged knows how to redisplay end, viewQuitScript: func() begin if currentView = checkView then begin checkView:SaveCheck(); openToOverview := nil; end else openToOverview := true; if target = nil and checkBookCursor <> nil then target := checkBookCursor:Entry(); :UnRegisterCardSoup(kSoupName); // nil out slots with run-time values checkBookSoup := nil; currentView := nil; checkBookCursor := nil; target := nil; ClearUndoStacks(); // any undo actions added will "grab" the card. end /* Here is some code you can use to make sure you've NIL'd out all relavant data from an app's base view after closing: call func(view) begin foreach slot, value in view do begin write(slot); write($:); write($\t); if value = view._parent then print("parent"); else if value = view._proto then print("proto"); else if value = GetRoot() then print("root"); else if value = view then print("self"); else print(value); end; end with (GetRoot().(kAppSymbol)) */, appAll: "All Checks" // used by Filing, checkBookSoup: nil // contains the checkbook union soup. Inited in viewSetupFormScript, target: nil // points to current soup entry. Maintained by // overview.viewSetupDoneScript and checkView.DisplayBook, RegisterCardSoup: func(soupName, soupIndexes, appSymbol, appObject) begin // returns a union soup for your app to use // first check for system provided function if functions.RegisterCardSoup then return RegisterCardSoup(soupName, soupIndexes, appSymbol, appObject); CreateAppSoup(soupName, soupIndexes, EnsureInternal([appSymbol]), EnsureInternal(appObject)); // ensure your soup will exists on stores which later become available. AddArraySlot(cardSoups, soupName); AddArraySlot(cardSOups, soupIndexes); // ensure your soup exists on all currently available stores local store; foreach store in GetStores() do if not store:IsReadOnly() and not store:HasSoup(soupName) then store:CreateSoup(soupName, soupIndexes); return GetUnionSoup(soupName); end, FolderChanged: func(soupName, oldLabel, newLabel) begin // the application may not be open when this message is // sent. Change all oldLabels in the soup to newLabel local soup := GetUnionSoup(kSoupName); if soup then begin // could have changed folders before ever running the app. local cursor := query(soup, {type: 'index, validTest: func(entry) begin return entry.labels = oldLabel; end }); // change the labels of each entry in the cursor to newLabel local e := cursor:Entry(); while e do begin e.labels := newLabel; EntryChange(e); e := cursor:Next(); end; BroadcastSoupChange(kSoupName); end; if folderTab then folderTab:UpdateFilter(oldLabel, newLabel); // redraw the filter end, viewFlags: 5, DisplayCheck: func(check) begin // Opens the checkView (if necessary) and displays check. // make sure cursor points to the displayed check if checkBookCursor:Entry() <> check then checkBookCursor:Goto(check); if currentView <> checkView then begin if currentView = overView then overview:Hide(); if not call kViewIsOpenFunc with (checkView) then checkView:Open(); // should only happen once end; checkView:DisplayCheck(check); if currentView <> checkView then checkView:Show(); // show after changing contents of the view end, DeleteActionScript: func(entryToDelete, targetView) begin // called when the user chooses Duplicate from the routing action button if not entryToDelete then GetRoot():SysBeep(); else begin checkView:Delete('DeleteCheck, [entryToDelete]); AddUndoAction('UndoDeleteCheck, [entryToDelete]); end; end, Redisplay: func() begin // displays the current check, if possible. Otherwise, // goes to the first check in the cursor and displays it. if target and target <> 'deleted and IsSoupEntry(target) then currentView:Dirty() // redisplay. Something might have changed. else begin checkBookCursor:Reset(); if currentView = checkView then begin if not checkBookCursor:Entry() then begin // no checks in this folder :DisplayOverview(); end else :DisplayCurrentCheck(); end else overview:DisplayFromCursor(); end; end, viewBounds: {top: 3, left: 0, right: 234, bottom: 335}, DateFind: func(findTime, comparison, results, scope, statusForm) begin if statusForm then statusForm:SetStatus("Searching in" && kAppName & $\u2026); // 2026 is unicode É local soup := GetUnionSoup(kSoupName); if soup then begin // the app could never have run // look for all entries with text containing what local cursor := Query(soup, {type: 'index, validTest: if comparison = 'dateBefore then func(entry) begin return entry.date < findTime; end else func(entry) begin return entry.date > findTime; end }); if cursor:Entry() then begin local ourResult := { _proto: GetRoot().soupFinder, owner: self, title: kAppName, findType: comparison, findTime: findTime, cursor: cursor, }; AddArraySlot(results, ourResult); end; end; end, AddCheckToSOup: func(newCheck) begin try checkbookSoup:AddToDefaultStore(newCheck); onexception |evt.ex| do begin // catch the exception so we return cleanly. A message will // already have been presented. We want the New button to unhilite. end; if not checkbookCursor:Goto(newCheck) then begin // not in this folder. Change to "All" folder so we can see it folderTab:UpdateFilter(labelsFilter, '_all); end; :DisplayCheck(newCheck); end, appObject: kAppObject // used by Filing, FilingChanged: func() begin :Redisplay(); end, CreateNewCheck: func() begin // creates a new check, adds it to the soup, and displays it. local newCheck := Clone(defaultCheck); newCheck.date := Time(); newCheck.number := :HighestCheckNumber() + 1; :AddCheckToSoup(newCheck); end, DisplayCurrentCheck: func() begin // displays the check the cursor points to // if there isn't anything in the cursor, display the overview local entry := checkbookCursor:Entry(); if not entry then checkbookCursor:Reset(); entry := checkbookCursor:Entry(); if not entry then :DisplayOverview(); else :DisplayCheck(entry); end, FilterChanged: func() begin :Redisplay(); end, labelsFilter: nil // current folder on display. Used by filing., routingFrame: { // used by InstallScript to set up routing action button print: { title: "Print Check", routeForm: 'printSlip, formats: [kCheckFormatSymbol], }, fax: { title: "Fax", routeForm: 'faxSlip, formats: [kCheckFormatSymbol], }, beam: { title: "Beam", routeForm: 'zapSlip, }, mail: { title: "Mail", routeForm: 'mailSlip, formats: [kCheckFormatSymbol], }, separator: nil, delete: { title: "Delete", routeScript: 'DeleteActionScript, }, duplicate: { title: "Duplicate", routeScript: 'DuplicateActionScript, }, card: ROM_cardAction, };, ShowFoundItem: func(entry, finder) begin if not checkbookCursor:Goto(entry) then begin // not in this folder. Change to "All" folder so we can see it folderTab:UpdateFilter(labelsFilter, '_all); end; :DisplayCheck(entry); end, viewScrollDownScript: func() begin // let the current view handle it currentView:viewScrollDownScript(); end, viewOverviewScript: func() begin // called when the user clicks the overview button if currentView = overview then // If the overview is open, and there is something to display, // display it. if not checkbookCursor:Entry() then GetRoot():SysBeep(); else :DisplayCurrentCheck() else begin // otherwise, switch to the overview :DisplayOverview(); end; end, checkBookCursor: nil // a cursor available to the whole application that points to checkBookSoup entries , PostParseCommand: func(taskTemplate) begin // called in response to the "Pay" request from IA local applicationWasOpen := (call kViewIsOpenFunc with (self)) <> nil; :Open(); // we might be closed; local newCheck := Clone(defaultCheck); newCheck.number := :HighestCheckNumber() + 1; newCheck.date := Time(); for i := 0 to Length(taskTemplate.input) - 1 do begin local template := taskTemplate.input[i]; if Isa(template, 'person) or isa(template, 'company) then newCheck.payee := taskTemplate.phrases[i]; else if Isa(template, 'parsed_number) then newCheck.amount := StringToNumber(template.value); else if Isa(template, 'date) then begin newCheck.date := StringToDate(template.value); newCheck.date := newCheck.date - newCheck.date MOD kMinutesPerDay; end; end; local assistView := BuildContext(pt_assistDialogProto); assistView:Open(); assistView:DisplayEntry(newCheck, applicationWasOpen); GetRoot().assistant:Close(); // close the IA slip end, appSymbol: kAppSymbol // needed for routing and filing, title: "Checkbook", nckMetaData: { soup: nil, // added at runtime name: nil, // added at runtime version: 1, defaultDefinitions: { textNumber: {label: "Check No.", path: 'number, size: 5, type: 'integer}, textDate: {label: "Date:", path: 'date, size: 8, type: 'string}, textPayee: {label: "To:", path: 'payee, size: 20, type: 'string}, textAmount: {label: "Amount:", path: 'amount, size: 10, type: 'real}, }, displayInfo: [ 'textNumber, 'textDate, 'textPayee, 'textAmount, ], editInfo: [ 'textNumber, 'textDate, 'textPayee, 'textAmount, ], exportInfo: [ 'textNumber, 'textDate, 'textPayee, 'textAmount, ], import: func(textFrame) begin // this routine is called from within Newton Connection // Therefore, don't use any routines from the application. This // routine must be standalone. // It converts a textual representation of a check to a soup entry. local soupFrame; local value; if textFrame.originalFrame then soupFrame := textFrame.originalFrame; else soupFrame := { payee: "", memo: "", amount: 0.0, number: 0, date: 0 }; soupFrame.payee := textFrame.textPayee; value := StringToNumber(textFrame.textAmount); if value then soupFrame.amount := value; value := Floor(StringToNumber(textFrame.textNumber)); if value then soupFrame.number := value; value := StringToDate(textFrame.textDate); if value then soupFrame.date := value - value MOD kMinutesPerDay; return soupFrame; end, export: func(soupFrame) begin local textFrame := {originalFrame: soupFrame}; textFrame.textNumber := if soupFrame.number then SPrintObject(soupFrame.number) else ""; textFrame.textDate := if soupFrame.date then ShortDateStr(soupFrame.date, 0); else ""; textFrame.textPayee := if soupFrame.payee then soupFrame.payee; else ""; textFrame.textAmount := if soupFrame.amount then SPrintObject(soupFrame.amount); else ""; return textFrame; end, }, HighestCheckNumber: func() begin local cursor := Query(checkBookSoup, {type: 'index, indexPath: 'number}); /* cursor:GotoKey({number: 999999}); // larger than any possible check number cursor:Prev(); // now points at the highest number local entry := cursor:Entry(); */ while cursor:Next() do begin end; local entry := cursor:Prev(); if entry and entry.number then return entry.number; else return 0; end, Find: func(what,results,scope,statusForm) begin if statusForm then statusForm:SetStatus("Searching in" && kAppName & $\u2026); // 2026 is unicode É local soup := GetUnionSoup(kSoupName); if soup then begin // the app could never have run // look for all entries with text containing what local cursor := Query(soup, {type: 'text, text: what}); if cursor:Entry() then begin local ourResult := { _proto: GetRoot().soupFinder, owner: self, title: kAppName, findType: 'text, findWords: [what], cursor: cursor, }; AddArraySlot(results, ourResult); end; end; end, viewScrollUpScript: func() begin // let the current view handle it currentView:viewScrollUpScript(); end, declareSelf: 'base, viewSetupFormScript: func() begin targetView := self; // used by Routing and Filing checkBookSoup := :RegisterCardSoup(kSoupName, kSoupIndexes, kAppSymbol, kAppObject); :AddNCKSupportIfNecessary(); // create a cursor which takes into account labelsFilter (for filing) checkBookCursor := Query(checkBookSoup, { type: 'index, indexPath: 'date, validTest: func(entry) begin return labelsFilter = '_all or entry.labels = labelsFilter; end, }); // generate random data if no checks exist if not CheckBookCursor:Entry() then begin // arrays used to generate random payees and memos local randomPayees := [ "Julie McKeehan", "Computer Literacy", "Neil Rhodes", "Apple Computer" ]; local randomMemos := [ "lunch", "equipment", "gift", "Inv# 56790", ]; for i := 1 to 20 do begin local randomCheck := { payee: randomPayees[Random(0, Length(randomPayees)-1)], memo: randomMemos[Random(0, Length(randomMemos)-1)], date: Time() - Random(0, 10) * kMinutesPerDay, number: 100 + i, amount: Random(100,500000)/100.00, //32.15, for instance }; randomCheck.date := randomCheck.date - randomCheck.date MOD kMinutesPerDay; checkBookSoup:AddToDefaultStore(randomCheck); end; end; // resize to fit this screen. Inset by one on top, left, and right local params := GetAppParams(); self.viewBounds := RelBounds( params.appAreaLeft + 1, params.appAreaTop + 1, Min(kMaxApplicationWidth, params.appAreaWidth - 2), Min(kMaxApplicationWidth, params.appAreaHeight - 1) ); // Open in the same state as when closed if target and not checkBookCursor:Goto(target) then checkBookCursor:Reset(); end , DuplicateActionScript: func(entryToDuplicate, targetView) begin // called when the user chooses Duplicate from the routing action button if not entryToDuplicate then GetRoot():SysBeep() else begin local newEntry := EntryCopy(entryToDuplicate, checkBookSoup); :DisplayCheck(newEntry); AddUndoAction('UndoDuplicateCheck, [newEntry]); end; end, currentView: nil // points to the checkView or the overview depending // on which one is currently open, UndoDeleteCheck: func(deletedCheck) begin checkBookSoup:AddToDefaultStore(deletedCheck); if checkbookCursor:Clone():Goto(deletedCheck) then :DisplayCheck(deletedCheck); // else leave the display alone end, printFormat: { // used for printing/faxing/mailing. See InstallScript // title that shows up in the Format picker // in the print or fax slip title: kAppName, // this could be a symbol for an auxilliary // information slip. See the auxForm sample code auxForm: nil, // symbol for a script that is called by // mail for a text only message to send textScript: 'GetTextForMail, // true if the user can attach a real // frame to the mail attachment: true, // a proto to get a coverPage for free! _proto: ROM_coverPageFormat, // the main format used for each page of // a print or fax output. mainFormat: printFormat_checkFormat, }, SetupRoutingSlip: func(fields) begin // called for routing when beaming/mailing fields.target := target; fields.title := :GetCheckAsText(target); end, viewclass: 74, FindSoupExcerpt: func(entry, finder) begin if finder.findType = 'dateBefore or finder.findType = 'dateAfter then return GetRoot().(kAppSymbol):GetCheckAsText(entry); else // call inherited version of FindSoupExcerpt :Parent():FindSoupExcerpt(entry, finder); end, defaultCheck: { // check which is cloned as a new check is created. payee: "", memo: "", amount: 0.00, number: 101, date: 0, }, openToOverview: true // true if overview should display on open, nil if checkView should display , debug: "checkBook", targetView: nil // used by Routing and Filing. Initialized in viewSetupFormScript, GetTextForMail: func(fields, check) begin // called by routing when user requests text version of message text := "Check #" & check.number & "\n"; text := text & "To:" && check.payee & "\n"; text := text & "Amount:" && FormattedNumberStr(check.amount, "%0.2f") & "\n"; text := text & "Memo:" && check.memo & "\n"; text := text & "Date:" && ShortDateStr(check.date, 0); return text; end, viewSetupChildrenScript: func() begin // open the view which was open when we closed. if openToOverview then overview.viewFlags := BOR(overview.viewFlags, vVisible); else checkView.viewFlags := BOR(checkView.viewFlags, vVisible); end, soupChanged: func(theSoupName) begin if call kViewIsOpenFunc with (self) then // the application is open :Redisplay() end, UnRegisterCardSoup: func(soupName) begin // first check for system provided function if functions.UnRegisterCardSoup then return UnRegisterCardSoup(soupName); local pos := ArrayPos(cardSoups, soupName, 0, func(x, y) ClassOf(y) = 'String and StrEqual(x, y)); if pos then ArrayRemoveCount(cardSoups, pos, 2); end }; // Before Script for "folderTab" // Copyright © 1993, 1994 by Apple Computer, Inc. All rights reserved. nil folderTab := /* child of checkBook */ {_proto: protoFolderTab, debug: "folderTab"}; // View folderTab is declared to checkBook // Before Script for "_view000" // Copyright © 1993, 1994 by Apple Computer, Inc. All rights reserved. nil _view000 := /* child of checkBook */ {_proto: protoStatus}; // Before Script for "_view001" // Copyright © 1993, 1994 by Apple Computer, Inc. All rights reserved. nil _view001 := /* child of _view000 */ {_proto: protoActionButton}; // Before Script for "_view002" // Copyright © 1993, 1994 by Apple Computer, Inc. All rights reserved. nil _view002 := /* child of _view000 */ {viewBounds: {left: -23, top: 2, right: -6, bottom: 15}, _proto: protoFilingButton }; // Before Script for "newButton" // Copyright © 1993, 1994 by Apple Computer, Inc. All rights reserved. nil newButton := /* child of _view000 */ {text: "New", buttonClickScript: func() begin base:CreateNewCheck(); end, viewBounds: {left: 25, top: 2, right: 55, bottom: 15}, _proto: protoTextButton, debug: "newButton" }; // After Script for "newButton" thisView := newButton; // set the bounds of the button so that it is to the right // of the clock and the correct height for the status bar // NOTE: this is the first "real" button, so argument to the // ButtonBounds function MUST be negative thisView.viewBounds := ButtonBounds(-(thisView.viewBounds.right - thisView.viewBounds.left)); // ---- File checkView.t ---- checkView := /* child of checkBook */ {viewFlags: 0, viewFormat: 336, viewBounds: {top: 80, left: 4, right: -4, bottom: 230}, viewJustify: 48, DisplayCheck: func(check) begin //displays a check in the checkView // save the previous entry if currentCheck then :SaveCheck(); SetValue(ckDate, 'text, ShortDateStr(check.date, 0)); SetValue(ckNumber, 'text, NumberStr(check.number)); SetValue(ckPayee, 'text, check.payee); SetValue(ckAmount, 'text, FormattedNumberStr((check.amount), "%0.2f")); SetValue(ckMemo, 'text, check.memo); self.currentCheck := check; target := check; // current soup entry. Used for routing and filing. // target is a slot in the base view. end;, currentCheck: nil, SaveCheck: func() begin if currentCheck then begin // reads the information from the input lines into the current // check and saves the entry into the soup. currentCheck.payee := ckPayee.text; currentCheck.memo := ckMemo.text; // StringToNumber can return NIL if the string is not a valid number // It would be a bad idea to have a NIL amount, or number. local value := StringToNumber(ckNumber.text); if value then begin // RIntToL converts a real to an integer currentCheck.number := RIntToL(value); end; value := StringToNumber(ckAmount.text); if value then currentCheck.amount := value; // StringToDate takes into account the current time. // thus, if the current time is 7:03 PM // StringToDate("5/5/93") returns number of minutes to 7:03 PM // on 5/5/93. // StringToDate can return NIL for an invalid date. value := StringToDate(ckDate.text); if value then // convert to 12:00 AM by truncating any minutes beyond 12 AM currentCheck.date := value - value mod kMinutesPerDay; EntryChange(currentCheck); // save in the soup self.currentCheck := nil; end; end, viewEffect: 1023009, viewShowScript: func() begin currentView := self; // currentView is in the base view end, viewHideScript: func() begin :SaveCheck(); end, DeleteCheck: func(entryToDelete) begin EntryRemoveFromSoup(entryToDelete); currentCheck := target := nil; checkBookCursor:Next(); if not checkBookCursor:Entry() then // they deleted the last entry in the soup checkBookCursor:Prev(); if not checkBookCursor:Entry() then begin// there are no more books in the soup GetRoot().(kAppSymbol):DisplayOverview(); end else GetRoot().(kAppSymbol):DisplayCurrentCheck(); end , viewScrollDownScript: func() begin local cursor := checkbookCursor; cursor:Next(); local entry := cursor:Entry(); if entry = nil then begin GetRoot():SysBeep(); cursor:Prev(); end else begin local bounds := :LocalBox(); :SlideEffect(- (bounds.bottom - bounds.top), 0, scrollDownSound, 'DisplayCheck, [entry] ); end; end, viewScrollUpScript: func() begin local cursor := checkbookCursor; cursor:Prev(); local entry := cursor:Entry(); if entry = nil then begin GetRoot():SysBeep(); cursor:Next(); end else begin local bounds := :LocalBox(); :SlideEffect(bounds.bottom - bounds.top, 0, scrollUpSound, 'DisplayCheck, [entry] ); end; end, viewclass: 74, debug: "checkView" }; // View checkView is declared to checkBook ckNumber := /* child of checkView */ {viewBounds: {top: 10, left: -60, right: -2, bottom: 35}, viewJustify: 8388640, viewFlags: 10753, _proto: protoInputLine, debug: "ckNumber" }; // View ckNumber is declared to checkView ckDate := /* child of checkView */ {viewBounds: {top: 0, left: -90, right: -2, bottom: 30}, viewJustify: 8396832, viewFlags: 67648033, _proto: protoInputLine, debug: "ckDate" }; // View ckDate is declared to checkView ckAmount := /* child of checkView */ {viewBounds: {top: 0, left: 12, right: -97, bottom: 0}, viewJustify: 8400944, viewFlags: 10753, _proto: protoInputLine, debug: "ckAmount" }; // View ckAmount is declared to checkView amountLabel := /* child of checkView */ {text: "$", viewBounds: {top: 0, left: -10, right: 0, bottom: 0}, viewJustify: 8402948, _proto: protoStaticText, debug: "amountLabel" }; ckPayee := /* child of checkView */ {viewBounds: {top: 10, left: 2, right: -2, bottom: 40}, viewJustify: 8396848, viewFlags: 14849, _proto: protoInputLine, debug: "ckPayee" }; // View ckPayee is declared to checkView payeeLabel := /* child of checkView */ {text: "Payee", viewBounds: {top: -10, left: 0, right: 50, bottom: 15}, viewJustify: 8398848 , _proto: protoStaticText, debug: "payeeLabel" }; ckMemo := /* child of checkView */ {viewBounds: {top: 0, left: 2, right: -120, bottom: 25}, viewJustify: 8396848, viewFlags: 14849, _proto: protoInputLine, debug: "ckMemo" }; // View ckMemo is declared to checkView memoLabel := /* child of checkView */ {text: "Memo", viewBounds: {top: -5, left: 0, right: 50, bottom: 10}, viewJustify: 8398848, _proto: protoStaticText, debug: "memoLabel" }; name := /* child of checkView */ {text: "Static Text", viewBounds: {left: 5, top: 2, right: 120, bottom: 14}, viewSetupFormScript: func() begin self.text := userConfiguration.name; end, _proto: protoStaticText, debug: "name" }; address := /* child of checkView */ {text: "Static Text", viewBounds: {left: 0, top: 0, right: 0, bottom: 12}, viewJustify: 8398336, viewSetupFormScript: func() begin self.text := userConfiguration.address; end, _proto: protoStaticText, debug: "address" }; cityState := /* child of checkView */ {text: "Static Text", viewBounds: {left: 0, top: 0, right: 0, bottom: 12}, viewJustify: 8398336, viewSetupFormScript: func() begin self.text := userConfiguration.cityZip; end, _proto: protoStaticText, debug: "cityState" }; // ---- Back in File mainlayout.t ---- // ---- File overview.t ---- overview := /* child of checkBook */ {viewFlags: 0, viewFormat: 256, viewBounds: {top: 15, left: 1, right: -1, bottom: -22}, viewJustify: 240, DisplayFromCursor: func() begin :FillRows(); :Dirty(); end, viewEffect: 1023009, viewShowScript: func() begin currentView := self; // currentView is in the base view target := nil; // no current soup entry displayed. end, viewSetupDoneScript: func() begin :DisplayFromCursor(); currentView := self; // currentView is in the base view target := nil; // no current soup entry displayed. end, viewSetupChildrenScript: func() begin // called before this view's children are created. local rowHeight := pt_cbEntryProto.viewBounds.bottom; local viewHeight := :LocalBox().bottom; self.numberRows := viewHeight div rowHeight; // resize to be an even multiple of the rowHeight (+1 for the line at the // bottom of each row). This way, ScrollEffect can scroll correctly. local newBounds := Clone(viewBounds); newBounds.bottom := viewBounds.bottom - (viewHeight - numberRows * rowHeight); SetValue(self, 'viewBounds, newBounds); // stepChildren is an array of cbEntryProto templates. // self is required here since the stepChildren slot doesn't exist // for a template with no children. self.stepChildren := Array(numberRows, pt_cbEntryProto); end, numberRows: nil, FillRows: func() begin // fill rows from the soup starting at the current cursor position // make a copy of checkBookCursor so we don't change it's location // in the soup local cursorCopy := checkBookCursor:Clone(); // Fill rows from the cursor in each cbEntryProto child view foreach child in :ChildViewFrames() do begin child:FillFromCheck(cursorCopy:Entry()); cursorCopy:Next(); end; end, DoScroll: func(scrollUp) begin // This method is called by ScrollEffect from ScrollDown or ScrollUp. :FillRows(); // dirty the children which were just scrolled in. local start; local finish; local children := :ChildViewFrames(); if scrollUp then begin start := 0; finish := :NumberRowsToScroll() - 1; end else begin start := Length(children) - :NumberRowsToScroll(); finish := Length(children) - 1; end; for i := start to finish do children[i]:Dirty(); end;, NumberRowsToScroll: func() begin return Max(1, numberRows div 2); end, viewSetupFormScript: func() begin end, viewScrollDownScript: func() begin if not checkbookCursor:Clone():Move(numberRows) then begin // there are no more checks beyond what is now visible GetRoot():SysBeep(); end else begin local numToScroll := :NumberRowsToScroll(); checkbookCursor:Move(numToScroll); :SlideEffect(-numToScroll * pt_CBEntryProto.viewBounds.bottom, 0, scrollDownSound, 'DoScroll, [nil] ); end; end, viewScrollUpScript: func() begin if not checkbookCursor:Clone():Prev() then begin // there are no more checks beyond what is now visible GetRoot():SysBeep(); end else begin local numToScroll := :NumberRowsToScroll(); checkbookCursor:Move(-numToScroll); if not checkbookCursor:Entry() then checkbookCursor:Next(); :SlideEffect(numToScroll * pt_CBEntryProto.viewBounds.bottom, 0, scrollUpSound, 'DoScroll, [true] ); end; end, viewclass: 74, debug: "overview" }; // View overview is declared to checkBook // ---- Back in File mainlayout.t ---- // ---- Beginning of non-used User Protos ---- // ---- File assistDialogProto ---- asistDialog := {viewBounds: {left: 0, top: 0, right: 194, bottom: 144}, applicationWasOpen: nil // true if the application was open before the user used IA, DisplayEntry: func(anEntry, appWasOpen) begin self.applicationWasOpen := appWasOpen; SetValue(assistDate.entryLine, 'text, ShortDateStr(anEntry.date, 0)); SetValue(assistAmount.entryLine, 'text, FormattedNumberStr(anEntry.amount, "%0.2f")); local names := :GetPayeeNames(anEntry.payee); assistPayee:SetLabelCommands(names); if names then SetValue(assistPayee.entryLine, 'text, names[0]); else SetValue(assistPayee.entryLine, 'text, ""); self.entry := anEntry; end, SaveEntry: func() begin local newCheck := entry; local value; value := StringToDate(assistDate.text); if value then // convert to 12:00 AM by truncating any minutes beyond 12 AM newCheck.date := value - value MOD kMinutesPerDay; newCheck.payee := assistPayee.entryLine.text; value := StringToNumber(assistAmount.entryLine.text); if value then newCheck.amount := value; GetRoot().(kAppSymbol):AddCheckToSoup(newCheck); end, viewJustify: 80, entry: nil, GetPayeeNames: func(aName) begin // returns an array of strings matching the input string (from the // Name soup) // SmartCFQuery("") causes an exception if StrLen(aName) = 0 then return nil; local cfEntries := SmartCFQuery(aName); if not cfEntries then return nil; return foreach cfEntry in cfEntries collect begin if cfEntry.name exists then cfEntry.name.first && cfEntry.name.last; else cfEntry.company; end; end, _proto: protoFloater, debug: "asistDialog" }; _view003 := /* child of asistDialog */ { buttonClickScript: func() begin inherited:buttonClickScript(); // close this floater. if not applicationWasOpen then GetRoot().(kAppSymbol):Close(); // close the application end, _proto: protoLargeClosebox }; _view004 := /* child of asistDialog */ {text: "Pay", buttonClickScript: func() begin :Parent():SaveEntry(); base:Close(); end, viewBounds: {top: 0, left: -32, right: -6, bottom: 0}, viewJustify: 8402950, _proto: protoTextButton }; assistDate := /* child of asistDialog */ {viewBounds: {left: 14, top: 26, right: 190, bottom: 48}, label: "Date:", _proto: protoLabelInputLine, debug: "assistDate" }; // View assistDate is declared to asistDialog assistPayee := /* child of asistDialog */ {viewBounds: {left: 14, top: 10, right: 190, bottom: 32}, viewJustify: 8396800, labelCommands: [], label: "To:", _proto: protoLabelInputLine, debug: "assistPayee" }; // View assistPayee is declared to asistDialog assistAmount := /* child of asistDialog */ {viewBounds: {left: 14, top: 10, right: 190, bottom: 32}, viewJustify: 8396800, label: "$:", _proto: protoLabelInputLine, debug: "assistAmount" }; // View assistAmount is declared to asistDialog // ---- File cbEntryProto ---- container := {viewFlags: 513, viewFormat: 337, viewBounds: {top: 0, left: 1, right: -1, bottom: 20}, viewJustify: 8240, currentCheck: nil, viewClickScript: func(unit) begin // when user clicks on a check in the overview, ask the // base view to display that check. if currentCheck then begin InkOff(unit); :Hilite(true); // turn on hiliting GetRoot().(kAppSymbol):DisplayCheck(currentCheck); :Hilite(nil); // turn off the hiliting. return true; end else return nil; end, FillFromCheck: func(check) begin // Fill static texts in the overview // if there are no entries it displays empty strings in the static texts // Doesn't use SetValue because we want to dirty by hand (for scrolling // to avoid unnecessary redraw). if check <> nil then begin ovDate.text := ShortDateStr(check.date, 0); ovNumber.text := NumberStr(check.number); ovPayee.text := check.payee; ovAmount.text := FormattedNumberStr((check.amount), "%0.2f"); end else begin ovDate.text := ""; ovNumber.text := ""; ovPayee.text := ""; ovAmount.text := ""; end; self.currentCheck := check; end;, viewclass: 74, debug: "container" }; ovDate := /* child of container */ {text: "10/15/93", viewBounds: {left: 0, top: 0, right: 55, bottom: 0}, viewJustify: 8388804, _proto: protoStaticText, debug: "ovDate" }; // View ovDate is declared to container ovNumber := /* child of container */ {text: "232", viewBounds: {left: 0, top: 0, right: 30, bottom: 0}, viewJustify: 8389829, _proto: protoStaticText, debug: "ovNumber" }; // View ovNumber is declared to container ovPayee := /* child of container */ {text: "Julie McKeehan", viewBounds: {top: 0, left: 90, right: -57, bottom: 0}, viewJustify: 8388852, _proto: protoStaticText, debug: "ovPayee" }; // View ovPayee is declared to container ovAmount := /* child of container */ {text: "12322.56", viewBounds: {left: 0, top: 0, right: 57, bottom: 0}, viewJustify: 8389829, _proto: protoStaticText, debug: "ovAmount" }; // View ovAmount is declared to container // ---- End of non-used User Protos ---- // ---- Beginning of section for non used Layout files ---- // ---- File checkView.t ---- checkView := {viewFlags: 0, viewFormat: 336, viewBounds: {top: 80, left: 4, right: -4, bottom: 230}, viewJustify: 48, DisplayCheck: func(check) begin //displays a check in the checkView // save the previous entry if currentCheck then :SaveCheck(); SetValue(ckDate, 'text, ShortDateStr(check.date, 0)); SetValue(ckNumber, 'text, NumberStr(check.number)); SetValue(ckPayee, 'text, check.payee); SetValue(ckAmount, 'text, FormattedNumberStr((check.amount), "%0.2f")); SetValue(ckMemo, 'text, check.memo); self.currentCheck := check; target := check; // current soup entry. Used for routing and filing. // target is a slot in the base view. end;, currentCheck: nil, SaveCheck: func() begin if currentCheck then begin // reads the information from the input lines into the current // check and saves the entry into the soup. currentCheck.payee := ckPayee.text; currentCheck.memo := ckMemo.text; // StringToNumber can return NIL if the string is not a valid number // It would be a bad idea to have a NIL amount, or number. local value := StringToNumber(ckNumber.text); if value then begin // RIntToL converts a real to an integer currentCheck.number := RIntToL(value); end; value := StringToNumber(ckAmount.text); if value then currentCheck.amount := value; // StringToDate takes into account the current time. // thus, if the current time is 7:03 PM // StringToDate("5/5/93") returns number of minutes to 7:03 PM // on 5/5/93. // StringToDate can return NIL for an invalid date. value := StringToDate(ckDate.text); if value then // convert to 12:00 AM by truncating any minutes beyond 12 AM currentCheck.date := value - value mod kMinutesPerDay; EntryChange(currentCheck); // save in the soup self.currentCheck := nil; end; end, viewEffect: 1023009, viewShowScript: func() begin currentView := self; // currentView is in the base view end, viewHideScript: func() begin :SaveCheck(); end, DeleteCheck: func(entryToDelete) begin EntryRemoveFromSoup(entryToDelete); currentCheck := target := nil; checkBookCursor:Next(); if not checkBookCursor:Entry() then // they deleted the last entry in the soup checkBookCursor:Prev(); if not checkBookCursor:Entry() then begin// there are no more books in the soup GetRoot().(kAppSymbol):DisplayOverview(); end else GetRoot().(kAppSymbol):DisplayCurrentCheck(); end , viewScrollDownScript: func() begin local cursor := checkbookCursor; cursor:Next(); local entry := cursor:Entry(); if entry = nil then begin GetRoot():SysBeep(); cursor:Prev(); end else begin local bounds := :LocalBox(); :SlideEffect(- (bounds.bottom - bounds.top), 0, scrollDownSound, 'DisplayCheck, [entry] ); end; end, viewScrollUpScript: func() begin local cursor := checkbookCursor; cursor:Prev(); local entry := cursor:Entry(); if entry = nil then begin GetRoot():SysBeep(); cursor:Next(); end else begin local bounds := :LocalBox(); :SlideEffect(bounds.bottom - bounds.top, 0, scrollUpSound, 'DisplayCheck, [entry] ); end; end, viewclass: 74, debug: "checkView" }; ckNumber := /* child of checkView */ {viewBounds: {top: 10, left: -60, right: -2, bottom: 35}, viewJustify: 8388640, viewFlags: 10753, _proto: protoInputLine, debug: "ckNumber" }; // View ckNumber is declared to checkView ckDate := /* child of checkView */ {viewBounds: {top: 0, left: -90, right: -2, bottom: 30}, viewJustify: 8396832, viewFlags: 67648033, _proto: protoInputLine, debug: "ckDate" }; // View ckDate is declared to checkView ckAmount := /* child of checkView */ {viewBounds: {top: 0, left: 12, right: -97, bottom: 0}, viewJustify: 8400944, viewFlags: 10753, _proto: protoInputLine, debug: "ckAmount" }; // View ckAmount is declared to checkView amountLabel := /* child of checkView */ {text: "$", viewBounds: {top: 0, left: -10, right: 0, bottom: 0}, viewJustify: 8402948, _proto: protoStaticText, debug: "amountLabel" }; ckPayee := /* child of checkView */ {viewBounds: {top: 10, left: 2, right: -2, bottom: 40}, viewJustify: 8396848, viewFlags: 14849, _proto: protoInputLine, debug: "ckPayee" }; // View ckPayee is declared to checkView payeeLabel := /* child of checkView */ {text: "Payee", viewBounds: {top: -10, left: 0, right: 50, bottom: 15}, viewJustify: 8398848 , _proto: protoStaticText, debug: "payeeLabel" }; ckMemo := /* child of checkView */ {viewBounds: {top: 0, left: 2, right: -120, bottom: 25}, viewJustify: 8396848, viewFlags: 14849, _proto: protoInputLine, debug: "ckMemo" }; // View ckMemo is declared to checkView memoLabel := /* child of checkView */ {text: "Memo", viewBounds: {top: -5, left: 0, right: 50, bottom: 10}, viewJustify: 8398848, _proto: protoStaticText, debug: "memoLabel" }; name := /* child of checkView */ {text: "Static Text", viewBounds: {left: 5, top: 2, right: 120, bottom: 14}, viewSetupFormScript: func() begin self.text := userConfiguration.name; end, _proto: protoStaticText, debug: "name" }; address := /* child of checkView */ {text: "Static Text", viewBounds: {left: 0, top: 0, right: 0, bottom: 12}, viewJustify: 8398336, viewSetupFormScript: func() begin self.text := userConfiguration.address; end, _proto: protoStaticText, debug: "address" }; cityState := /* child of checkView */ {text: "Static Text", viewBounds: {left: 0, top: 0, right: 0, bottom: 12}, viewJustify: 8398336, viewSetupFormScript: func() begin self.text := userConfiguration.cityZip; end, _proto: protoStaticText, debug: "cityState" }; // End of output