Model subclass: #Spreadsheet
instanceVariableNames: 'mySpreadSheet value '
classVariableNames: ''
poolDictionaries: ''
category: 'Spreadsheets'!
!Spreadsheet methodsFor: 'private'!
mySpreadSheet: newSpreadSheet
"assign a spread sheet"
mySpreadSheet := newSpreadSheet.!
value: aValue
"update value and broadcast the change to dependencies."
value := aValue.
self changed: #value.! !
!Spreadsheet methodsFor: 'accessing'!
cell: whichCell
"get the value of a cell"
(whichCell > mySpreadSheet size) ifTrue:
[ DialogView warn: 'The cell reference is out of range; defaulting to a value of 0.'. ^0. ].
^mySpreadSheet at: whichCell.!
mySpreadSheet
^mySpreadSheet.!
value
^value.! !
!Spreadsheet methodsFor: 'operations'!
cell: whichCell put: dataItem
"fill a cell with some data"
| index |
index := (mySpreadSheet size) + 1.
(whichCell > index) ifTrue:
[ DialogView warn: 'You must use contiguous cells. The cell will not be set as requested.'. ^False ].
mySpreadSheet growToAtLeast: whichCell.
mySpreadSheet at: whichCell put: dataItem.
self updateValue.!
cells: anArray
"assign mySpreadSheet a fixed array"
mySpreadSheet := anArray.
self updateValue.!
updateValue
"force subclasses to implement this method"
^self subclassResponsibility.! !
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
Spreadsheet class
instanceVariableNames: ''!
!Spreadsheet class methodsFor: 'initializing'!
type: typeOfSheet
"create a new spreadsheet of a specified type and return it"
| newSheet view|
newSheet := 0. " initialize newSheet"
view := SpreadsheetViewContainer new. "create our attached view"
(typeOfSheet = #sum) ifTrue: "test whether we should build a summing spreadsheet"
[ newSheet := SumSpreadsheet new. " create the new spreadsheet"
newSheet mySpreadSheet: Array new. " initialize its spread sheet array to empty"
view openOn: newSheet labeled: 'Sum'. ]. " attach its view"
(typeOfSheet = #average) ifTrue: " likewise for averaging spreadsheets..."
[ newSheet := AverageSpreadsheet new.
newSheet mySpreadSheet: Array new.
view openOn: newSheet labeled: 'Average'. ].
(newSheet = 0) "if the user asked for neither a sum nor average sheet, warn and abort"
ifTrue: [ DialogView warn: 'Only #sum and #average types of spreadsheets are currently supported.'. ^nil.]
ifFalse: [ ^newSheet. ] " otherwise, we're ready to go"!
type: typeOfSheet with: sheetArray
"create a new linked spreadsheet of a specified type and return it"
| newSheet view|
newSheet := 0. " initialize our new spreadsheet to 0 (failure)"
view := SpreadsheetViewContainer new. " create our new view"
(typeOfSheet = #sum) ifTrue: " test which type of spreadsheet to create"
[ newSheet := LinkedSumSpreadsheet new mySpreadSheet: sheetArray. "create the spreadsheet with its spreadsheet array of linked sheets"
view openOn: newSheet labeled: 'Linked Sum'. ]. " attach our new view"
(typeOfSheet = #average) ifTrue: " likewise for averaging spreadsheets..."
[ newSheet := LinkedAverageSpreadsheet new mySpreadSheet: sheetArray.
view openOn: newSheet labeled: 'Linked Average'. ].
(newSheet = 0) " if the user picked neither averaging nor summing sheets, warn and abort"
ifTrue: [ DialogView warn: 'Only #sum and #average types of spreadsheets are currently supported.' . ^nil. ]
ifFalse: " otherwise, everything's ready to go..."
[ sheetArray do: [ :aSheet | aSheet addDependent: newSheet. ]. " create dependencies so we know when to update our own value"
newSheet updateValue. " go ahead and initially update our value"
^newSheet. ] . " return the prepared sheet"!
type: typeOfSheet with: sheet1 cell: cell1 with: sheet2 cell: cell2
"create a new spreadsheet linked to two specific cells and return it"
| newSheet view newArray|
newSheet := 0. " initialize the new spreadsheet"
view := SpreadsheetViewContainer new. "create our new view"
newArray := Array with: (SpreadsheetCell new sheet: sheet1; cell: cell1) with: (SpreadsheetCell new sheet: sheet2; cell: cell2). "create a temporary array of spreadsheet/cell pairs"
(typeOfSheet = #sum) ifTrue: " test what type of spreadsheet to create"
[ newSheet := LinkedCellSumSpreadsheet new mySpreadSheet: newArray. " create the new summing sheet with its initial array of spreadsheet/cell pairs"
view openOn: newSheet labeled: '2 Cell Sum'. ]. " attach the view"
(typeOfSheet = #average) ifTrue: " do likewise for averaging spreadsheets"
[ newSheet := LinkedCellAverageSpreadsheet new mySpreadSheet: newArray.
view openOn: newSheet labeled: '2 Cell Average'.] .
(newSheet = 0) " if the user picked something other than summing or averaging, warn and abort"
ifTrue: [ DialogView warn: 'Only #sum and #average types of spreadsheets are currently supported.' ]
ifFalse:
[ sheet1 addDependent: newSheet. "create dependencies on the linked spreadsheets, so we know when to update our value"
sheet2 addDependent: newSheet.
newSheet updateValue. " go ahead and update our initial value"
^newSheet. ] . " we're done"! !
Spreadsheet subclass: #SumSpreadsheet
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Spreadsheets'!
!SumSpreadsheet methodsFor: 'operations'!
updateValue
"update value with the sum of the spreadsheet"
value := 0.
mySpreadSheet do:
[ :cell | (cell = nil) ifFalse: [value := value + cell ]].
self value: value.
^value.! !
Spreadsheet subclass: #AverageSpreadsheet
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Spreadsheets'!
!AverageSpreadsheet methodsFor: 'operations'!
updateValue
"update value with the average value of the spreadsheet's cells"
value := 0.
mySpreadSheet do: [ :cell | (cell = nil) ifFalse: [value := value + cell ]].
self value: value / (mySpreadSheet size).
^value.! !
Object subclass: #SpreadsheetCell
instanceVariableNames: 'sheet cell '
classVariableNames: ''
poolDictionaries: ''
category: 'Spreadsheets'!
!SpreadsheetCell methodsFor: 'accessing'!
cell
^cell.!
cell: aCell
cell := aCell.!
sheet
^sheet.!
sheet: aSheet
sheet := aSheet.! !