1from Foundation import * 2from ToDoCell import * 3from ToDoItem import * 4from SelectionNotifyMatrix import * 5 6ToDoItemChangedNotification = "ToDoItemChangedNotification" 7 8class ToDoDocument (NSDocument): 9 calendar = objc.IBOutlet() 10 dayLabel = objc.IBOutlet() 11 itemList = objc.IBOutlet() 12 statusList = objc.IBOutlet() 13 14 15 __slots__ = ('_dataFromFile', '_activeDays', '_currentItems', '_selectedItem', '_selectedItemEdited') 16 17 def rowSelected_(self, notification): 18 row = notification.object().selectedRow() 19 20 if row == -1: 21 #print 'No rowSelected?' 22 return 23 24 self._selectedItem = self._currentItems.objectAtIndex_(row) 25 26 if not isinstance(self._selectedItem, ToDoItem): 27 self._selectedItem = None 28 29 NSNotificationCenter.defaultCenter().postNotificationName_object_userInfo_(ToDoItemChangedNotification, self._selectedItem, None) 30 31 def init(self): 32 NSDocument.init(self) 33 self._activeDays = None 34 self._currentItems = None 35 self._selectedItem = None 36 self._selectedItemEdited = 0 37 self._dataFromFile = None 38 39 return self 40 41 def __del__(self): # dealloc in Objective-C code 42 43 NSNotificationCenter.defaultCenter().removeObserver_(self) 44 45 def selectedItem(self): 46 return self._selectedItem 47 48 def windowNibName(self): 49 return "ToDoDocument" 50 51 def windowControllerDidLoadNib_(self, aController): 52 # NSDocument.windowControllerDidLoadNib_(self, aController) 53 54 self.setHasUndoManager_(0) 55 self.itemList.setDelegate_(self) 56 57 index = self.statusList.cells().count() 58 while index: 59 index -= 1 60 61 aCell = ToDoCell.alloc().init() 62 aCell.setTarget_(self) 63 aCell.setAction_('itemStatusClicked:') 64 self.statusList.putCell_atRow_column_(aCell, index, 0) 65 66 if self._dataFromFile: 67 self.loadDocWithData_(self._dataFromFile) 68 self._dataFromFile = None 69 else: 70 self.loadDocWithData_(None) 71 72 NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, 'rowSelected:', RowSelectedNotification, self.itemList) 73 NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, 'rowSelected:', RowSelectedNotification, self.statusList) 74 75 def loadDocWithData_(self, data): 76 if data: 77 dct = NSUnarchiver.unarchiveObjectWithData_(data) 78 self.initDataModelWithDictinary_(dct) 79 dayEnum = self._activeDays.keyEnumerator() 80 now = NSDate.date() 81 82 itemDate = dayEnum.nextObject() 83 while itemDate: 84 itemArray = self._activeDays.objectForKey_(itemDate) 85 itemEnum = itemArray.objectEnumerator() 86 87 anItem = itemEnum.nextObject() 88 while anItem: 89 if (isinstance(anItem, ToDoItem) 90 and anItem.secsUntilNotify() 91 and anItem.status() == INCOMPLETE): 92 due = anItem.day().addTimeInterfval_(anItem.secondsUntilDue()) 93 elapsed = due.timeIntervalSinceDate_(now) 94 if elapsed > 0: 95 self.setTimerForItem_(anItem) 96 else: 97 #print "Past due" 98 NSBeep() 99 NSRunAlertPanel("To Do", "%s on %s is past due!"%( 100 anItem.itemName(), 101 due.descriptionWithCalendarFormat_timeZone_locale_( 102 "%b %d, %Y at %I:%M %p", 103 NSTimeZone.localTimeZone(), 104 None 105 ) 106 ), None, None, None) 107 anItem.setSecsUntilNotify_(0) 108 anItem = itemEnum.nextObject() 109 110 itemDate = dayEnum.nextObject() 111 else: 112 self.initDataModelWithDictionary_(None) 113 114 self.selectItemAtRow_(0) 115 self.updateLists() 116 117 self.dayLabel.setStringValue_( 118 self.calendar.selectedDay().descriptionWithCalendarFormat_timeZone_locale_( 119 "To Do on %a %B %d %Y", 120 NSTimeZone.defaultTimeZone(), 121 None)) 122 123 def initDataModelWithDictionary_(self, aDict): 124 if aDict: 125 self._activeDays = aDict 126 else: 127 self._activeDays = NSMutableDictionary.alloc().init() 128 129 date = self.calendar.selectedDay() 130 self.setCurrentItems_(self._activeDays.objectForKey_(date)) 131 132 def setCurrentItems_(self, newItems): 133 if newItems: 134 self._currentItems = newItems.mutableCopy() 135 else: 136 numRows, numCols = self.itemList.getNumberOfRows_columns_(None, None) 137 self._currentItems = NSMutableArray.alloc().initWithCapacity_(numRows) 138 139 for d in range(numRows): 140 self._currentItems.addObject_("") 141 142 def updateLists(self): 143 numRows = self.itemList.cells().count() 144 145 for i in range(numRows): 146 if self._currentItems: 147 thisItem = self._currentItems.objectAtIndex_(i) 148 else: 149 thisItem = None 150 #print ">>> object %d is %s %s"%(i, thisItem, isinstance(thisItem, ToDoItem)) 151 152 if isinstance(thisItem, ToDoItem): 153 if thisItem.secsUntilDue(): 154 due = thisItem.day().addTimeInterval_(thisItem.secsUntilDue()) 155 else: 156 due = None 157 158 self.itemList.cellAtRow_column_(i, 0).setStringValue_(thisItem.itemName()) 159 self.statusList.cellAtRow_column_(i, 0).setTimeDue_(due) 160 self.statusList.cellAtRow_column_(i, 0).setTriState_(thisItem.status()) 161 else: 162 self.itemList.cellAtRow_column_(i, 0).setStringValue_("") 163 self.statusList.cellAtRow_column_(i, 0).setTitle_("") 164 self.statusList.cellAtRow_column_(i, 0).setImage_(None) 165 166 def saveDocItems(self): 167 if self._currentItems: 168 cnt = self._currentItems.count() 169 170 for i in range(cnt): 171 anItem = self._currentItems.objectAtIndex_(i) 172 if isinstance(anItem, ToDoItem): 173 self._activeDays.setObject_forKey_(self._currentItems, anItem.day()) 174 break 175 176 def controlTextDidEndEditing_(self, notif): 177 if not self._selectedItemEdited: 178 return 179 180 row = self.itemList.selectedRow() 181 newName = self.itemList.selectedCell().stringValue() 182 183 if isinstance(self._currentItems.objectAtIndex_(row), ToDoItem): 184 prevNameAtIndex = self._currentItems.objectAtIndex_(row).itemName() 185 if newName == "": 186 self._currentItems.replaceObjectAtRow_withObject_(row, "") 187 elif prevNameAtIndex != newName: 188 self._currentItems.objectAtRow_(row).setItemName_(newName) 189 elif newName != "": 190 newItem = ToDoItem.alloc().initWithName_andDate_(newName, self.calendar.selectedDay()) 191 self._currentItems.replaceObjectAtIndex_withObject_(row, newItem) 192 193 self._selectedItem = self._currentItems.objectAtIndex_(row) 194 195 if not isinstance(self._selectedItem, ToDoItem): 196 self._selectedItem = None 197 198 self.updateLists() 199 self._selectedItemEdited = 0 200 self.updateChangeCount_(NSChangeDone) 201 202 NSNotificationCenter.defaultCenter( 203 ).postNotificationName_object_userInfo_( 204 ToDoItemChangedNotification, self._selectedItem, None) 205 206 def selectedItemModified(self): 207 if self._selectedItem: 208 self.setTimerForItem_(self._selectedItem) 209 210 self.updateLists() 211 self.updateChangeCount_(NSChangeDone) 212 213 def calendarMatrix_didChangeToDate_(self, matrix, date): 214 self.saveDocItems() 215 216 if self._activeDays: 217 self.setCurrentItems_(self._activeDays.objectForKey_(date)) 218 else: 219 #print "calenderMatrix:didChangeToDate: -> no _activeDays" 220 pass 221 222 self.dayLabel.setStringValue_( 223 date.descriptionWithCalendarFormat_timeZone_locale_( 224 "To Do on %a %B %d %Y", NSTimeZone.defaultTimeZone(), 225 None)) 226 self.updateLists() 227 self.selectedItemAtRow_(0) 228 229 def selectedItemAtRow_(self, row): 230 self.itemList.selectCellAtRow_column_(row, 0) 231 232 def controlTextDidBeginEditing_(self, notif): 233 self._selectedItemEdited = 1 234 235 def dataRepresentationOfType_(self, aType): 236 self.saveDocItems() 237 238 return NSArchiver.archivedDataWithRootObject_(self._activeDays) 239 240 def loadRepresentation_ofType_(self, data, aType): 241 if selfcalendar: 242 self.loadDocWithData_(data) 243 else: 244 self._dataFromFile = data 245 246 return 1 247 248 @objc.IBAction 249 def itemStatusClicked_(self, sender): 250 row = sender.selectedRow() 251 cell = sender.cellAtRow_column_(row, 0) 252 item = self._currentItems.objectAtIndex_(row) 253 254 if isinstance(item, ToDoItem): 255 # print "changing status to", cell.triState() 256 item.setStatus_(cell.triState()) 257 self.setTimerForItem_(item) 258 259 self.updateLists() 260 self.updateChangeCount_(NSChangeDone) 261 262 NSNotificationCenter.defaultCenter().postNotificationName_object_userInfo_( 263 ToDoItemChangedNotification, item, None) 264 265 def setTimerForItem_(self, anItem): 266 if anItem.secsUntilNotify() and anItem.status() == INCOMPLETE: 267 notifyDate = anItem.day().addTimeInterval_(anItem.secsUntilDue() - anItem.secsUntilNotify()) 268 269 aTimer = NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_( 270 notifyDate.timeIntervalSinceNow(), 271 self, 272 'itemTimerFired:', 273 anItem, 274 False) 275 anItem.setTimer_(aTimer) 276 else: 277 anItem.setTimer_(None) 278 279 def itemTimerFired_(self, timer): 280 #print "Timer fired for ", timer 281 anItem = timer.userInfo() 282 dueDate = anItem.day().addTimeInterval_(anItem.secsUntilDue()) 283 284 NSBeep() 285 286 NSRunAlertPanel("To Do", "%s on %s"%( 287 anItem.itemName(), dueDate.descriptionWithCalendarFormat_timeZone_locale_( 288 "%b %d, %Y at %I:%M: %p", NSTimeZone.defaultTimeZone(), None), 289 ), None, None, None) 290 anItem.setSecsUntilNotify_(0) 291 self.setTimerForItem_(anItem) 292 self.updateLists() 293 294 NSNotificationCenter.defaultCenter().postNotificationName_object_userInfo_( 295 ToDoItemChangedNotification, 296 anItem, 297 None) 298 299 def selectItemAtRow_(self, row): 300 self.itemList.selectCellAtRow_column_(row, 0) 301 302if __name__ == "__main__": 303 x = ToDoDocument.alloc() 304 print x 305 print x.init() 306