136 lines
5.2 KiB
Smalltalk
136 lines
5.2 KiB
Smalltalk
"Instance Variables:
|
|
- yearToPrint: The year to print the calendar of
|
|
- stream: The stream used to print the calendar
|
|
- monthsOfYear: A collection of all the months of yearToPrint, for example January 1969, February 1969, and so on
|
|
- currentMonths: Group of 3 months under print, for example from January to March or April to June, and so on
|
|
- monthOfYearCurrentDate: A collection that associates a month with the date to print for that month. It is used to
|
|
know which day number should be printed for each month when iterating over the day of weeks of each row"
|
|
Object subclass: #CalendarPrinter
|
|
instanceVariableNames: 'yearToPrint stream monthsOfYear currentMonths monthOfYearCurrentDate'
|
|
classVariableNames: ''
|
|
poolDictionaries: ''
|
|
category: 'CalendarPrinter'
|
|
|
|
CalendarPrinter class>>printOnTranscriptForYearNumber: aYearNumber
|
|
(self for: (GregorianYear number: aYearNumber) on: Transcript) value
|
|
|
|
CalendarPrinter class>>for: aYear on: aStream
|
|
^self new initializeFor: aYear on: aStream
|
|
|
|
initializeFor: aYear on: aStream
|
|
yearToPrint := aYear.
|
|
stream := aStream.
|
|
monthsOfYear := yearToPrint months.
|
|
monthOfYearCurrentDate := monthsOfYear collect: [ :aMonthOfYear | aMonthOfYear firstDate ].
|
|
|
|
value
|
|
"Prints the year number (header) and then its months"
|
|
self
|
|
printHeader;
|
|
printMonths.
|
|
|
|
printHeader
|
|
"Prints the year number centered"
|
|
self center: yearToPrint number printString in: self numberOfCharactersPerLine.
|
|
stream newLine; newLine.
|
|
|
|
printMonths
|
|
"Prints each group of 3 months, for example from January to March, then April to June and so on"
|
|
(January to: December by: 3*month) do: [ :aMonth | self printMonthsStartingOn: aMonth ].
|
|
|
|
printMonthsStartingOn: aMonth
|
|
"For each group of 3 months starting in aMonth, prints the name of the month (header),
|
|
the name of the days of the week (Mo Tu ...), and then the day numbers"
|
|
currentMonths := aMonth to: aMonth next next.
|
|
self
|
|
printMonthsHeader;
|
|
printDaysOfWeekHeader;
|
|
printDayNumbers.
|
|
|
|
printMonthsHeader
|
|
"Prints the current group of 3 months names, centered"
|
|
currentMonths
|
|
do: [ :currentMonth | self center: currentMonth printString in: self numberOfCharactersPerMonth ]
|
|
separatedBy: [ stream space: 3 ].
|
|
stream newLine.
|
|
|
|
printDaysOfWeekHeader
|
|
"Prints the names of the days of week for each month of the current group of 3 months"
|
|
currentMonths
|
|
do: [ :currentMonth | self printOneMonthDaysOfWeekHeader ]
|
|
separatedBy: [ stream space: 3 ].
|
|
stream newLine.
|
|
|
|
printOneMonthDaysOfWeekHeader
|
|
"Prints the name of the days of week"
|
|
(Sunday to: Saturday)
|
|
do: [ :aDayOfWeek | stream nextPutAll: (aDayOfWeek printString first: 2) ]
|
|
separatedBy: [ stream space ]
|
|
|
|
printDayNumbers
|
|
"While there are day numbers to print, prints them in a row"
|
|
[self hasDayNumbersToPrint] whileTrue: [ self printDayNumbersRow ].
|
|
|
|
hasDayNumbersToPrint
|
|
"If any of the group of 3 months currently printing has day numbers to print returns true, otherwise false"
|
|
^currentMonths anySatisfy: [ :currentMonth | self isCurrentDateAtSameMonthOfYearAs: currentMonth ]
|
|
|
|
isCurrentDateAtSameMonthOfYearAs: currentMonth
|
|
"Returns true if the date to print for currentMonth is actually for the currentMonth"
|
|
^(self currentDateOf: currentMonth) month = currentMonth
|
|
|
|
printDayNumbersRow
|
|
"For each month of the group of 3, prints a row of day numbers"
|
|
currentMonths
|
|
do: [ :currentMonth | self printDayNumbersRowOf: currentMonth ]
|
|
separatedBy: [ stream space: 3 ].
|
|
stream newLine
|
|
|
|
printDayNumbersRowOf: currentMonth
|
|
"Prints the day numbers of the current week"
|
|
(Sunday to: Saturday)
|
|
do: [ :aDayOfWeek | self printDayNumberOf: currentMonth for: aDayOfWeek ]
|
|
separatedBy: [ stream space ]
|
|
|
|
printDayNumberOf: currentMonth for: aDayOfWeek
|
|
"If the current date of the current month corresponds to aDayOfWeeks, prints its day number,
|
|
if not, leaves a space
|
|
This is important to leave the spaces in the first row and last row for those day of week
|
|
that do not have a day number related"
|
|
| currentDate |
|
|
currentDate := self currentDateOf: currentMonth.
|
|
(self hasToPrint: currentDate of: currentMonth for: aDayOfWeek)
|
|
ifTrue: [
|
|
currentDate dayNumber printOn: stream length: 2 zeroPadded: false.
|
|
self calculateNextCurrentDateOf: currentMonth ]
|
|
ifFalse: [ stream space: 2 ]! !
|
|
|
|
hasToPrint: aDate of: aCurrentMonth for: aDayOfWeek
|
|
"Returns whether aDate is part of aCurrentMonth and its day of week is aDayOfWeek.
|
|
It is used to decide whether to print the date day number or leave an space"
|
|
^(aDate month = aCurrentMonth) and: [aDate day = aDayOfWeek]
|
|
|
|
currentDateOf: currentMonth
|
|
"Returns the date to print for currentMonth"
|
|
^monthOfYearCurrentDate at: currentMonth number
|
|
|
|
calculateNextCurrentDateOf: currentMonth
|
|
"Changes the date to print of the currentMonth to the next date"
|
|
monthOfYearCurrentDate at: currentMonth number put: (self currentDateOf: currentMonth) next
|
|
|
|
center: stringToCenter in: aNumberOfCharacters
|
|
"Prints stringToCenter centered in a line of aNumberOfCharacters total"
|
|
| centerStart |
|
|
centerStart := aNumberOfCharacters - stringToCenter size // 2.
|
|
stream
|
|
space: centerStart;
|
|
nextPutAll: stringToCenter;
|
|
space: aNumberOfCharacters - centerStart - stringToCenter size
|
|
|
|
numberOfCharactersPerLine
|
|
"Returns the number of characters per line"
|
|
^66
|
|
|
|
numberOfCharactersPerMonth
|
|
"Returns the number of character per month"
|
|
^20
|