1from Cocoa import *
2
3gNumDaysInMonth = ( 0, 31, 28, 31, 30, 21, 30, 31, 31, 30, 31, 30, 31 )
4
5def isLeap(year):
6    return (((year % 4) == 0 and ((year % 100) != 0)) or (year % 400) == 0)
7
8class CalendarMatrix (NSMatrix):
9    lastMonthButton = objc.IBOutlet()
10    monthName = objc.IBOutlet()
11    nextMonthButton = objc.IBOutlet()
12
13    __slots__ = ('_selectedDay', '_startOffset')
14
15    def initWithFrame_(self, frameRect):
16        self._selectedDay = None
17        self._startOffset = 0
18
19        cell = NSButtonCell.alloc().initTextCell_("")
20        now  = NSCalendarDate.date()
21
22        cell.setShowsStateBy_(NSOnOffButton)
23        self.initWithFrame_mode_prototype_numberOfRows_numberOfColumns_(
24            frameRect, NSRadioModeMatrix, cell, 5, 7)
25
26        count = 0
27        for i in range(6):
28            for j in range(7):
29                val = self.cellAtRow_column_(i, j)
30                if val:
31                    val.setTag_(count)
32                count += 1
33
34        self._selectedDay = NSCalendarDate.dateWithYear_month_day_hour_minute_second_timeZone_(
35                now.yearOfCommonEra(),
36                now.monthOfYear(),
37                now.dayOfMonth(),
38                0,
39                0,
40                0,
41                NSTimeZone.localTimeZone())
42        return self
43
44
45    @objc.IBAction
46    def choseDay_(self, sender):
47        prevSelDate = self.selectedDay()
48        selDay = self.selectedCell().tag() - self._startOffset + 1
49
50        selDate = NSCalendarDate.dateWithYear_month_day_hour_minute_second_timeZone_(
51                prevSelDate.yearOfCommonEra(),
52                prevSelDate.monthOfYear(),
53                selDay,
54                0,
55                0,
56                0,
57                NSTimeZone.localTimeZone())
58        self.setSelectedDay_(selDate)
59        self.highlightTodayIfVisible()
60
61        if self.delegate().respondsToSelector_('calendarMatrix:didChangeToDate:'):
62            self.delegate().calendarMatrix_didChangeToDate_(
63                self, selDate)
64
65
66    @objc.IBAction
67    def monthChanged_(self, sender):
68        thisDate = self.selectedDay()
69        currentYear = thisDate.yearOfCommonEra()
70        currentMonth = thisDate.monthOfYear()
71
72        if sender is self.nextMonthButton:
73            if currentMonth == 12:
74                currentMonth = 1
75                currentYear += 1
76            else:
77                currentMonth += 1
78        else:
79            if currentMonth == 1:
80                currentMonth = 12
81                currentYear -= 1
82            else:
83                currentMonth -= 1
84
85        self.setSelectedDay_(NSCalendarDate.dateWithYear_month_day_hour_minute_second_timeZone_(currentYear, currentMonth, 1, 0, 0, 0, NSTimeZone.localTimeZone()))
86        self.refreshCalendar()
87        self.choseDay_(self)
88
89    def setSelectedDay_(self, newDay):
90        self._selectedDay = newDay
91
92    def selectedDay(self):
93        return self._selectedDay
94
95    def refreshCalendar(self):
96
97        selDate = self.selectedDay()
98        currentMonth = selDate.monthOfYear()
99        currentYear = selDate.yearOfCommonEra()
100
101        firstOfMonth = NSCalendarDate.dateWithYear_month_day_hour_minute_second_timeZone_(
102                    currentYear,
103                    currentMonth,
104                    1,
105                    0,
106                    0,
107                    0,
108                    NSTimeZone.localTimeZone())
109        self.monthName.setStringValue_(
110            firstOfMonth.descriptionWithCalendarFormat_("%B %Y"))
111        daysInMonth = gNumDaysInMonth[currentMonth]
112
113        if (currentMonth == 2) and isLeap(currentYear):
114            daysInMonth += 1
115
116        self._startOffset = firstOfMonth.dayOfWeek()
117
118        dayLabel = 1
119
120        for i in range(42):
121            cell = self.cellWithTag_(i)
122            if cell is None:
123                continue
124
125            if i < self._startOffset or i >= (daysInMonth + self._startOffset):
126                # blank out unused cells in the matrix
127                cell.setBordered_(False)
128                cell.setEnabled_(False)
129                cell.setTitle_("")
130                cell.setCellAttribute_to_(NSCellHighlighted, False)
131            else:
132                # Fill in valid days in the matrix
133                cell.setBordered_(True)
134                cell.setEnabled_(True)
135                cell.setFont_(NSFont.systemFontOfSize_(12))
136                cell.setTitle_(str(dayLabel))
137                dayLabel += 1
138                cell.setCellAttribute_to_(NSCellHighlighted, False)
139
140        self.selectCellWithTag_(selDate.dayOfMonth() + self._startOffset - 1)
141        self.highlightTodayIfVisible()
142
143
144    def highlightTodayIfVisible(self):
145        now = NSCalendarDate.date()
146        selDate = self.selectedDay()
147
148        if (selDate.yearOfCommonEra() == now.yearOfCommonEra()
149                and selDate.monthOfYear() == now.monthOfYear()
150                and selDate.dayOfMonth() == now.dayOfMonth()):
151            aCell = self.cellWithTag_(
152                now.dayOfMonth() + self._startOffset - 1)
153            aCell.setHighlightsBy_(NSMomentaryChangeButton)
154            aCell.setCellAttribute_to_(NSCellHighlighted, True)
155
156    def awakeFromNib(self):
157        self.setTarget_(self)
158        self.setAction_('choseDay:')
159        self.setAutosizesCells_(True)
160        self.refreshCalendar()
161        self.choseDay_(self)
162