From VisualWorks®, 7.6 of February 1, 2008 on February 1, 2008 at 12:47:33 pm (Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned. Choose terminate or close.'] <class> <name>LoanCalculator</name> <environment>Examples</environment> <super>UI.Model</super> <private>false</private> none principal paymentsPerYear years regularPayment percent computePaymentP <imports></imports> <category>Examples-Help</category> <attributes> <package>LoanCalculator-Example</package> </attributes> </class> <comment> Examples.LoanCalculator
LoanCalculator is a loan calculator model, used by LoanCalculatorExample. Instance Variables: principal <ValueHolder with: Float> comment paymentsPerYear <ValueHolder with: Integer> Twelve years <ValueHolder with: Number> The term of the loan regularPayment <ValueHolder with: Float> The payment amount percent <ValueHolder with: Float> The interest rate on the loan computePaymentP <ValueHolder with: Boolean> Whether or not to compute and display the payment amount
</comment> <class> <name>LoanCalculatorExample</name> <environment>Examples</environment> <super>UI.ApplicationModel</super> <private>false</private> none calculator <imports></imports> <category>Examples-Help</category> <attributes> <package>LoanCalculator-Example</package> </attributes> </class> <comment> Examples.LoanCalculatorExample
LoanCalculatorExample is the user interface for a Loan Calculator. This example demonstrates the use of input fields, and a domain model to coordinate the values underlying the constituent widgets in a user interface. The work of calculating and displaying the loan amortization is done by Amortizer, which uses a callback to the domain model to retrieve data required for the calculation. Instance Variables: calculator <LoanCalculator> The object that does the real work and provides the actual models for the widgets in the interface
</comment> <class> <name>Amortizer</name> <environment>Examples</environment> <super>UI.ApplicationModel</super> <private>false</private> none reportValue loan rate sumInt sumAmort accumInt balance yearTable totalTable <imports></imports> <category>Examples-Help</category> <attributes> <package>LoanCalculator-Example</package> </attributes> </class> <comment> Examples.Amortizer
Amortizer is used by LoanCalculator to generate a report detailing the repayment of a loan with interest. Instance Variables: reportValue <ValueHolder with: String> Holds the report being generated loan <LoanCalculator> The instance of LoanCalculator served by this instance of Amortizer rate <Float> Interest rate for the calculation sumInt <Float> Running sum of the interest paid during a year sumAmort <Float> Running sum of the amortization during a year accumInt <Float> Running sum of the amount paid in interest balance <Float> Running balance remaining on the principal yearTable <OrderedCollection of: Array> Holds a year worth of the report in structured form totalTable <Array of: Array> Holds the annual summary portion of the report in structured form
</comment> <methods> Examples.LoanCalculator <category>private</category>
changedData computePaymentP value ifTrue: [self computePayment]
computePayment | rate | rate := percent value asFloat / paymentsPerYear value / 100. ^regularPayment value: (((principal value * rate) / (1.0 - (( rate+1) ** (paymentsPerYear value negated * years value)))) roundTo: 0.01).
</methods> <methods> Examples.LoanCalculator <category>aspects</category>
computePaymentP ^computePaymentP
payment ^regularPayment
paymentsPerYear ^paymentsPerYear
percent ^percent
principal ^principal
years ^years
</methods> <methods> Examples.LoanCalculator <category>initialize-release</category>
initialize regularPayment := 0 asValue. paymentsPerYear := 12 asValue. percent := 8.2 asValue. principal := 0 asValue. years := 30 asValue. computePaymentP := true asValue. computePaymentP onChangeSend: #changedData to: self. (Array with: principal with: percent with: years with: paymentsPerYear) do: [:v | v onChangeSend: #changedData to: self].
</methods> <methods> Examples.LoanCalculator <category>actions</category>
computePrincipal | rate | regularPayment isNil ifTrue: [^self]. rate := percent value asFloat / paymentsPerYear value / 100. ^principal value: (((regularPayment value / rate) * (1.0 - (1.0 / (( rate+1) ** (paymentsPerYear value * years value))))) roundTo: 0.01).
</methods> <methods> Examples.LoanCalculator class <category>instance creation</category>
new "Create a new initialized LoanCalculator" ^super new initialize
</methods> <methods> Examples.LoanCalculatorExample <category>binding</category>
aspectFor: aKey ^calculator perform: aKey
</methods> <methods> Examples.LoanCalculatorExample <category>initialize-release</category>
calculator: aCalc calculator := aCalc
initialize calculator := LoanCalculator new
</methods> <methods> Examples.LoanCalculatorExample <category>actions</category>
doAmortize (Amortizer new) loan: calculator; report; open.
doComputePrincipal calculator computePrincipal
</methods> <methods> Examples.Amortizer <category>private</category>
amortize totalTable := Array new: loan years value. balance := loan principal value. accumInt := 0. rate := loan percent value asFloat / loan paymentsPerYear value / 100. 1 to: loan years value do: [:i | self computeYear: i]
computePeriod: period withPayment: pay | interest amortized payment| balance = 0 ifTrue: [^self]. balance > pay ifTrue: [payment := pay] ifFalse: [payment := balance +( (rate*balance) roundTo: 0.01)]. interest := balance*rate roundTo: 0.01. accumInt := accumInt + interest. sumInt := sumInt + interest. amortized := payment - interest. sumAmort := sumAmort + amortized. balance := balance - amortized. yearTable add: (Array with: interest with: amortized with: balance with: accumInt)
computeYear: yearNumber sumInt := sumAmort := 0.0. yearTable := OrderedCollection new. 1 to: loan paymentsPerYear value do: [:period | self computePeriod: period withPayment: loan payment value]. totalTable at: yearNumber put: (Array with: yearTable with: (Array with: sumInt with: sumAmort)).
report | s year pm fmtString | reportValue == nil ifTrue: [reportValue := String new asValue]. totalTable == nil ifTrue: [self amortize]. s := (String new: 1024) writeStream. 1 to: totalTable size do: [:y | s cr. s nextPutAll: (#NumberA << #examples >> ' No.') asString. s nextPutAll: (#InterestA << #examples >> ' Interest') asString. s nextPutAll: (#AmortizedA << #examples >> ' Amortized') asString. s nextPutAll: (#BalanceA << #examples >> ' Balance') asString. s nextPutAll: (#TotInterestA << #examples >> ' Tot Interest') asString. s cr. fmtString := (#FmtStringA << #examples >> '#########.##') asString. year := (totalTable at: y) at: 1. 1 to: year size do: [:p | pm := year at: p. s nextPutAll: (PrintConverter print: p formattedBy: '###'). s nextPutAll: (PrintConverter print: (pm at: 1) formattedBy: fmtString). s nextPutAll: (PrintConverter print: (pm at: 2) formattedBy: fmtString). s nextPutAll: (PrintConverter print: (pm at: 3) formattedBy: fmtString). s nextPutAll: (PrintConverter print: (pm at: 4) formattedBy: fmtString). s cr]. s cr. s nextPutAll: (#YearA << #examples >> 'yr.') asString. year := (totalTable at: y) at: 2. s nextPutAll: (PrintConverter print: y formattedBy: '##'). s nextPutAll: (PrintConverter print: (year at: 1) formattedBy: fmtString). s nextPutAll: (PrintConverter print: (year at: 2) formattedBy: fmtString). s cr; cr]. reportValue value: s contents. totalTable := nil.
</methods> <methods> Examples.Amortizer <category>initialize-release</category>
loan: aLoan loan := aLoan
</methods> <methods> Examples.Amortizer <category>aspects</category>
reportValue ^reportValue
</methods> <methods> Examples.LoanCalculatorExample class <category>interface specs</category>
windowSpec "Tools.UIPainter new openOnClass: self andSelector: #windowSpec" <resource: #canvas> ^#(#{UI.FullSpec} #window: #(#{UI.WindowSpec} #label: ' ' #min: #(#{Core.Point} 376 131 ) #max: #(#{Core.Point} 1152 900 ) #bounds: #(#{Graphics.Rectangle} 512 384 888 515 ) ) #component: #(#{UI.SpecCollection} #collection: #( #(#{UI.LabelSpec} #layout: #(#{Core.Point} 16 14 ) #name: #lblPrincipal #label: #(#{Kernel.UserMessage} #key: #PrincipalC #defaultString: 'Principal:' #catalogID: #examples ) ) #(#{UI.LabelSpec} #layout: #(#{Core.Point} 263 13 ) #name: #lblRate #label: #(#{Kernel.UserMessage} #key: #RateC #defaultString: 'Rate:' #catalogID: #examples ) ) #(#{UI.LabelSpec} #layout: #(#{Core.Point} 31 99 ) #name: #lblPayment #label: #(#{Kernel.UserMessage} #key: #PaymentC #defaultString: 'Payment:' #catalogID: #examples ) ) #(#{UI.LabelSpec} #layout: #(#{Core.Point} 17 46 ) #name: #lblYears #label: #(#{Kernel.UserMessage} #key: #YearsC #defaultString: 'Years:' #catalogID: #examples ) ) #(#{UI.InputFieldSpec} #layout: #(#{Graphics.Rectangle} 96 11 214 33 ) #name: #principal #model: #principal #type: #number ) #(#{UI.InputFieldSpec} #layout: #(#{Graphics.Rectangle} 305 12 368 35 ) #name: #percent #model: #percent #type: #number ) #(#{UI.InputFieldSpec} #layout: #(#{Graphics.Rectangle} 96 45 138 68 ) #name: #years #model: #years #numChars: 3 #type: #number ) #(#{UI.InputFieldSpec} #layout: #(#{Graphics.Rectangle} 96 97 218 123 ) #name: #payment #model: #payment #type: #number ) #(#{UI.ActionButtonSpec} #layout: #(#{Graphics.Rectangle} 216 9 244 35 ) #name: #btnComputePrincipal #model: #doComputePrincipal #tabable: false #label: '?' ) #(#{UI.CheckBoxSpec} #layout: #(#{Core.Point} 9 99 ) #name: #ckbComputePayment #model: #computePaymentP #tabable: false ) #(#{UI.ActionButtonSpec} #layout: #(#{Graphics.Rectangle} 270 97 336 126 ) #name: #btnAmortize #model: #doAmortize #tabable: false #label: #(#{Kernel.UserMessage} #key: #AmortizeC #defaultString: 'Amortize' #catalogID: #examples ) #isDefault: false ) ) ) )
</methods> <methods> Examples.Amortizer class <category>interface specs</category>
windowSpec "UIPainter new openOnClass: self andSelector: #windowSpec" <resource: #canvas> ^#(#FullSpec #window: #(#WindowSpec #label: ' ' #min: #(#Point 50 50 ) #max: #(#Point 1152 900 ) #bounds: #(#Rectangle 338 407 975 766 ) ) #component: #(#SpecCollection #collection: #( #(#TextEditorSpec #layout: #(#LayoutFrame 12 0 5 0 -12 1 -3 1 ) #model: #reportValue #style: #fixed ) ) ) )
</methods> "Imported Classes:" self error: 'Attempting to file-in parcel imports. Choose terminate or close' <class> <name>Model</name> <environment>UI</environment> <super>Core.Object</super> <private>false</private> none dependents <imports></imports> <category>Kernel-Objects</category> <attributes> <package>Kernel-Objects</package> </attributes> </class> <class> <name>ApplicationModel</name> <environment>UI</environment> <super>UI.Model</super> <private>false</private> none builder uiSession eventHandlers savedWindowInformation <imports></imports> <category>UIBuilder-Framework</category> <attributes> <package>UIBuilder-Framework</package> </attributes> </class>