Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
CalendarController.m
/* |
File: CalendarController.h |
Abstract: Controls a calendar model object. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
Computer, Inc. ("Apple") in consideration of your agreement to the |
following terms, and your use, installation, modification or |
redistribution of this Apple software constitutes acceptance of these |
terms. If you do not agree with these terms, please do not use, |
install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Computer, |
Inc. may be used to endorse or promote products derived from the Apple |
Software without specific prior written permission from Apple. Except |
as expressly stated in this notice, no other rights or licenses, express |
or implied, are granted by Apple herein, including but not limited to |
any patent rights that may be infringed by your derivative works or by |
other works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
Copyright © 2006 Apple Computer, Inc., All Rights Reserved |
*/ |
#import "CalendarController.h" |
#import "Calendar.h" |
#import "DayController.h" |
#import <CalendarStore/CalendarStore.h> |
static int DaysPerWeek = 7; // just in case you want to display a different number of days per week, ha-ha |
// CalendarController is a traditional Cocoa controller that encapsulates a Calendar view of events. |
// Calendar is the owner of the Calendar.nib file and has a view and window. The model is a collection of calendar years. |
// Each calendar has an array of months, and each month has an array of weeks. The Calendar view is a box containing tiled subviews. |
// Each subview represents a day in the current month. The day view consists of a composite view and controller. |
// The content of each controller is set to one of the models of a day. |
// Instances of Calendar observe changes to the iCal events. When events are added or removed from iCal, |
// the CalendarController adds and removes those objects from the day models, consequently updating the |
// view of the current month. |
// This class also provides methods for moving one year forward and backward, and moving one month forward and backward. |
@implementation CalendarController |
- (id)init |
{ |
self = [super init]; |
if (self) { |
_calendarYears = [[NSMutableArray array] retain]; |
// Initially create the current year, and add years later as needed--as events are added the dates are checked. |
NSCalendarDate *today = [NSCalendarDate calendarDate]; |
NSCalendarDate *year = [NSCalendarDate dateWithYear:[today yearOfCommonEra] |
month:1 day:1 hour:0 minute:0 second:0 |
timeZone:[today timeZone]]; |
[_calendarYears addObject:[self _createCalendarYear:year]]; |
//NSLog(@"calendarYears=%@", [_calendarYears description]); |
// Load my window and view |
if (![NSBundle loadNibNamed:@"Calendar.nib" owner:self]) { |
NSLog(@"failed to load Calendar.nib"); |
} |
[window setBackgroundColor:[NSColor whiteColor]]; |
NSRect superFrame = [view frame]; |
_dayControllers = [[NSMutableArray array] retain]; |
int i; |
float x = 0.0, y = superFrame.size.height; |
float w = superFrame.size.width/7; |
float h = superFrame.size.height/5; |
for (i = 0; i < 5; i++){ |
int j; |
for (j= 0; j < 7; j++){ |
DayController *dayCtlr = [[DayController alloc] init]; |
[_dayControllers addObject:dayCtlr]; |
[[dayCtlr view] setFrame:NSMakeRect(x, y - h, w, h)]; |
[view addSubview:[dayCtlr view]]; // will retain view |
x += w-1; |
} |
y -= h-1; // the last frame height |
x = 0.0; |
} |
[self setYearObject:[self firstYear]]; |
} |
return self; |
} |
- (void)dealloc { |
[_calendarYears release]; |
[_dayControllers release]; |
[model release]; |
[super dealloc]; |
} |
// Returns the data source used by this Calendar. |
- (id)model |
{ |
return model; |
} |
// Sets the receiver's data source to dataSource. |
- (void)setModel:(id)anObject |
{ |
// Observe changes to Event records maintained by the model. |
// Remove the receiver as an observer of the old data source |
[model removeObserver:self forKeyPath:@"events"]; |
// Remove all events belonging to the existing model from the calendar controller and views |
[self removeEvents:[model events]]; |
[model release]; |
model = [anObject retain]; |
// Add events from the new model to the calendar controller and views |
[self addEvents:[model events]]; |
// Add the receiver as an observer of the events array using a key path |
[model addObserver:self forKeyPath:@"events" |
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL]; |
} |
- (id)firstYear |
{ |
return [_calendarYears objectAtIndex:0]; |
} |
// Convenience methods for testing |
- (id)firstMonth |
{ |
if ([_calendarYears count] > 0){ |
NSArray *months = [[_calendarYears objectAtIndex:0] valueForKey:@"months"]; |
return [months objectAtIndex:0]; |
} |
return nil; |
} |
// Accessor Methods |
- (id)window |
{ |
return window; |
} |
- (id)year |
{ |
return _year; |
} |
- (void)displayToday |
{ |
NSCalendarDate *today = [NSCalendarDate calendarDate]; |
[self setYearObject:[self yearWithDate:today]]; |
[self setMonth:[[_year valueForKey:@"months"] objectAtIndex:([today monthOfYear]-1)]]; |
} |
- (void)setYearObject:(id)anObject |
{ |
// No need to retain it, it is an object in the calendar year array |
_year = anObject; |
[self setMonth:[[_year valueForKey:@"months"] objectAtIndex:0]]; // defaults to the first month of the year |
} |
- (id)nextYear |
{ |
int nextIndex; |
if (_year == nil) |
nextIndex = 0; |
else |
nextIndex = [_calendarYears indexOfObject:_year] + 1; |
if (nextIndex >= [_calendarYears count]) |
nextIndex = 0; // wrap around |
[self setYearObject:[_calendarYears objectAtIndex:nextIndex]]; |
return _year; |
} |
- (id)previousYear |
{ |
int nextIndex; |
if (_year == nil) |
nextIndex = 0; |
else |
nextIndex = [_calendarYears indexOfObject:_year] - 1; |
if (nextIndex < 0) |
nextIndex = [_calendarYears count]-1; // wrap around |
[self setYearObject:[_calendarYears objectAtIndex:nextIndex]]; |
return _year; |
} |
- (id)month |
{ |
return _month; |
} |
- (void)setMonth:(id)anObject |
{ |
//NSLog(@"setMonth: anObject=%@", [anObject valueForKey:@"date"]); |
// No need to retain it, it is an object in the current year |
_month = anObject; |
// Set the controller models so that the first month of the year is displayed |
NSEnumerator *weekEnumerator = [[_month valueForKey:@"weeks"] objectEnumerator]; |
NSDictionary *week; |
NSEnumerator *controllerEnumerator = [_dayControllers objectEnumerator]; |
while (week = [weekEnumerator nextObject]){ |
[[controllerEnumerator nextObject] setModel:[week valueForKey:@"Sun"]]; |
[[controllerEnumerator nextObject] setModel:[week valueForKey:@"Mon"]]; |
[[controllerEnumerator nextObject] setModel:[week valueForKey:@"Tue"]]; |
[[controllerEnumerator nextObject] setModel:[week valueForKey:@"Wed"]]; |
[[controllerEnumerator nextObject] setModel:[week valueForKey:@"Thu"]]; |
[[controllerEnumerator nextObject] setModel:[week valueForKey:@"Fri"]]; |
[[controllerEnumerator nextObject] setModel:[week valueForKey:@"Sat"]]; |
} |
id controller; |
while (controller = [controllerEnumerator nextObject]){ |
[controller setModel:nil]; // unused controller-view pairs |
} |
} |
// Returns the next month object. May wrap to the first month of the first year if there is no next year. |
- (id)nextMonth |
{ |
//NSLog(@"nextMonth _year=%@ _month=%@", [_year valueForKey:@"date"], [_month valueForKey:@"date"]); |
int nextIndex; |
if (_month == nil) |
nextIndex = 0; |
else |
nextIndex = [[_year valueForKey:@"months"] indexOfObject:_month] + 1; |
if (nextIndex >= [[_year valueForKey:@"months"] count]){ |
// Go to the last month of the previous year |
(void)[self nextYear]; |
nextIndex = 0; // wrap around |
} |
[self setMonth:[[_year valueForKey:@"months"] objectAtIndex:nextIndex]]; |
//NSLog(@"nextMonth index=%d", nextIndex); |
return _month; |
} |
// Returns the previous month object. May wrap to the last month of the last year if there is no previous year. |
- (id)previousMonth |
{ |
int nextIndex; |
if (_month == nil) |
nextIndex = 0; |
else |
nextIndex = [[_year valueForKey:@"months"] indexOfObject:_month] - 1; |
if (nextIndex < 0){ |
// Go to the last month of the previous year |
(void)[self previousYear]; |
nextIndex = [[_year valueForKey:@"months"] count] - 1; |
} |
[self setMonth:[[_year valueForKey:@"months"] objectAtIndex:nextIndex]]; |
//NSLog(@"previousMonth index=%d", nextIndex); |
return _month; |
} |
// Returns the array of calendar years. |
- (id)calendarYears |
{ |
return _calendarYears; |
} |
// Returns the day model for the specified date. |
- (id)dayWithDate:(NSCalendarDate *)date |
{ |
id year = [self yearWithDate:date]; |
if (year == nil) return nil; |
// find the day |
id month = [[year valueForKey:@"months"] objectAtIndex:[date monthOfYear]-1]; |
int weekOfMonth; // value of 0 through 4 or 5 |
{ |
int dayOfMonth = [date dayOfMonth]; |
NSCalendarDate *m = [NSCalendarDate dateWithYear:[date yearOfCommonEra] |
month:[date monthOfYear] day:1 hour:0 minute:0 second:0 |
timeZone:[date timeZone]]; |
int firstDayOfWeek = [m dayOfWeek]; |
weekOfMonth = (dayOfMonth + firstDayOfWeek - 1)/DaysPerWeek; |
} |
id week = [[month valueForKey:@"weeks"] objectAtIndex:weekOfMonth]; |
id day = [week valueForKey:[date descriptionWithCalendarFormat:@"%a"]]; |
return day; |
} |
// Return the days in the specified date range. Used to get the days for a multi-day event. |
- (NSMutableArray *)daysFromDate:(NSCalendarDate *)startDate toDate:(NSCalendarDate *)endDate |
{ |
NSMutableArray *days = [NSMutableArray array]; |
int ii, dd, mm; |
// Nothing to compute if there's no start date |
if ((startDate == nil) || [startDate isEqual:[NSNull null]]) |
return nil; |
// Always add the first day of the event |
[days addObject:[self dayWithDate:startDate]]; |
// Check for multi-day event |
//NSLog(@"endDate=%@ startDate=%@", [endDate description], [startDate description]); |
if ((endDate != nil) && ![endDate isEqual:[NSNull null]] && ([startDate dayOfCommonEra] < [endDate dayOfCommonEra])){ |
[endDate years:NULL months:NULL days:NULL hours:NULL minutes:&mm seconds:NULL sinceDate:startDate]; |
dd = (mm-1)/1440; // adjust by one minute for all day events |
NSCalendarDate *nextDate = startDate; |
for (ii = 0; ii < dd; ii++){ |
nextDate =[nextDate dateByAddingYears:0 months:0 days:1 hours:0 minutes:0 seconds:0]; |
[days addObject:[self dayWithDate:nextDate]]; |
} |
} |
return days; |
} |
// Returns the year model for the specified date |
- (id)yearWithDate:(NSCalendarDate *)date |
{ |
if ((date == nil) || [date isEqual:[NSNull null]]) return nil; |
NSEnumerator *yearEnumerator = [_calendarYears objectEnumerator]; |
id year; |
// find the matching year |
for (year = [yearEnumerator nextObject]; |
(year != nil) && ([date yearOfCommonEra] != [[year valueForKey:@"date"] yearOfCommonEra]); |
year = [yearEnumerator nextObject]){ |
} |
return year; |
} |
// Adding and Removing Events |
// Adds an array of events to the calendar. |
- (void)addEvents:(NSArray *)events |
{ |
NSEnumerator *eventEnumerator = [events objectEnumerator]; |
id event; |
while (event = [eventEnumerator nextObject]){ |
[self addEvent:event]; |
} |
} |
// Adds a single event to the calendar. |
- (void)addEvent:(id)event |
{ |
// Convert dates to calendar date values |
NSCalendarDate *startDate = [[event valueForKey:@"startDate"] dateWithCalendarFormat:nil timeZone:nil]; |
NSCalendarDate *endDate = [[event valueForKey:@"endDate"] dateWithCalendarFormat:nil timeZone:nil]; |
// Check to see if you need to add the year for this event |
if ([self yearWithDate:startDate] == nil){ |
NSCalendarDate *year = [NSCalendarDate dateWithYear:[startDate yearOfCommonEra] |
month:1 day:1 hour:0 minute:0 second:0 |
timeZone:[startDate timeZone]]; |
// Add the new year and then sort the years by date |
[_calendarYears addObject:[self _createCalendarYear:year]]; |
id dateDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES] autorelease]; |
[_calendarYears sortUsingDescriptors:[NSArray arrayWithObject:dateDescriptor]]; |
/* |
{ |
NSEnumerator *yearEnumerator = [_calendarYears objectEnumerator]; |
id aYear; |
while (aYear = [yearEnumerator nextObject]){ |
NSLog(@"year=%d", [[aYear valueForKey:@"date"] yearOfCommonEra]); |
} |
} |
*/ |
} |
NSMutableArray *days = [self daysFromDate:startDate toDate:endDate]; |
[self addEvent:event toDays:days]; |
return; |
} |
// Adds a multi-day event to the specified days on the calendar. |
- (void)addEvent:(id)event toDays:(NSArray *)days |
{ |
NSEnumerator *dayEnumerator = [days objectEnumerator]; |
id day; |
while (day = [dayEnumerator nextObject]){ |
id events = [day mutableArrayValueForKey:@"events"]; |
if (events == nil){ |
[day setValue:[NSMutableArray array] forKey:@"events"]; |
events = [day mutableArrayValueForKey:@"events"]; |
} |
[events addObject:event]; |
[day setValue:event forKey:@"currentEvent"]; // select the last added event |
} |
// Observe changes to the start and end dates |
[event addObserver:self forKeyPath:@"startDate" |
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) |
context:NULL]; |
[event addObserver:self forKeyPath:@"endDate" |
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) |
context:NULL]; |
return; |
} |
// Removes the array of events from the calendar. |
- (void)removeEvents:(NSArray *)events |
{ |
NSEnumerator *eventEnumerator = [events objectEnumerator]; |
id event; |
while (event = [eventEnumerator nextObject]){ |
[self removeEvent:event]; |
} |
} |
// Removes a single event from the calendar. |
- (void)removeEvent:(id)event |
{ |
NSCalendarDate *startDate = [[event valueForKey:@"startDate"] dateWithCalendarFormat:nil timeZone:nil]; |
NSCalendarDate *endDate = [[event valueForKey:@"endDate"] dateWithCalendarFormat:nil timeZone:nil]; |
NSMutableArray *days = [self daysFromDate:startDate toDate:endDate]; |
[self removeEvent:event fromDays:days]; |
} |
// Removes a multi-day event from the specified days of the calendar. |
- (void)removeEvent:(id)event fromDays:(NSArray *)days |
{ |
NSEnumerator *dayEnumerator = [days objectEnumerator]; |
id day; |
while (day = [dayEnumerator nextObject]){ |
id events = [day mutableArrayValueForKey:@"events"]; |
[events removeObject:event]; |
} |
// Remove the calendar as an observer of the start and end date |
[event removeObserver:self forKeyPath:@"startDate"]; |
[event removeObserver:self forKeyPath:@"endDate"]; |
return; |
} |
// KVO Methods |
// Observers changes to the data source. When records are added and removed they are added and removed from the calendar |
// model and calendar views are updated via Cocoa Bindings. |
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context |
{ |
// #warning Workaround for observer method change dictionary ValueChangeKind |
// NOTE: This method is currently being invoked without the change dictionary set as expected. The method is invoked |
// repeatedly with the NSKeyValueChangeKindKey equal to NSKeyValueChangeSetting, none of the other types of changes are |
// sent. The NSKeyValueChangeNewKey contains ALL the records, not just the added ones. Hence there is a workaround below |
// that can be removed if this issue is fixed. |
// 04-06-13 Still appears to be a bug in the Tiger seed release. |
NSLog(@"observeValueForKeyPath:... keyPath=%@ object=%@", keyPath, (object == model) ? @"model" : [object description]); |
// The model's events array changed |
if ([object isKindOfClass:[Calendar class]] && [keyPath isEqual:keyPath]){ |
NSLog(@"newRecords=%@", [[[change valueForKey:NSKeyValueChangeNewKey] valueForKey:@"title"] description]); |
NSLog(@"oldRecords=%@", [[[change valueForKey:NSKeyValueChangeOldKey] valueForKey:@"title"] description]); |
NSLog(@"change=%d", [[change valueForKey:NSKeyValueChangeKindKey] intValue]); |
// Work around is to compare the two arrays and figure out if this is a change, remove, or add operation |
int changeKind = [[change valueForKey:NSKeyValueChangeKindKey] intValue]; |
id newRecords = [change valueForKey:NSKeyValueChangeNewKey]; |
id oldRecords = [change valueForKey:NSKeyValueChangeOldKey]; |
NSMutableArray *delta = nil; |
if ([newRecords count] > [oldRecords count]){ |
// guess that a record was added |
delta = [NSMutableArray arrayWithArray:newRecords]; |
[delta removeObjectsInArray:oldRecords]; |
changeKind = NSKeyValueChangeInsertion; |
} |
else if ([newRecords count] < [oldRecords count]){ |
// guess that a record was removed |
delta = [NSMutableArray arrayWithArray:oldRecords]; |
[delta removeObjectsInArray:newRecords]; |
changeKind = NSKeyValueChangeRemoval; |
} |
else{ |
// This is probably a wrong conclusion because a record could have been replaced. In which case, |
// invoking _didAddRecords:forEntityName: on all the old and new records is harmless because it will |
// just mark records that don't have primaryKeys yet (won't harm exisitng records). |
changeKind = NSKeyValueChangeSetting; |
} |
if (changeKind == NSKeyValueChangeSetting){ |
//NSLog(@"change=NSKeyValueChangeSetting"); |
[self addEvents:[change valueForKey:NSKeyValueChangeNewKey]]; |
} |
if (changeKind == NSKeyValueChangeInsertion){ |
//NSLog(@"change=NSKeyValueChangeInsertion"); |
[self addEvents:delta]; |
} |
if (changeKind == NSKeyValueChangeRemoval){ |
//NSLog(@"change=NSKeyValueChangeRemoval"); |
[self removeEvents:delta]; |
} |
if (changeKind == NSKeyValueChangeReplacement){ |
//NSLog(@"change=NSKeyValueChangeReplacement"); |
[self removeEvents:[change valueForKey:NSKeyValueChangeOldKey]]; |
[self addEvents:[change valueForKey:NSKeyValueChangeNewKey]]; |
} |
} |
// A property of a record changed |
else if ([object isKindOfClass:[CalEvent class]] && ([[change valueForKey:NSKeyValueChangeKindKey] intValue] == NSKeyValueChangeSetting)){ |
NSLog(@"The UI or the calendar model (originated by iCal) changed a CalEvent property..."); |
// Assumes the start or end date of an event changed |
if ([keyPath isEqual:@"startDate"] || [keyPath isEqual:@"endDate"]){ |
NSCalendarDate *oldDate = [change valueForKey:NSKeyValueChangeOldKey]; |
NSLog(@"oldDate=%@", [oldDate description]); |
NSMutableArray *days; |
if ([keyPath isEqual:@"startDate"]) |
days = [self daysFromDate:oldDate toDate:[object valueForKey:@"endDate"]]; |
else |
days = [self daysFromDate:[object valueForKey:@"startDate"] toDate:oldDate]; |
[self removeEvent:object fromDays:days]; |
[self addEvent:object]; |
} |
// Any other types of changes are handled by Cocoa Bindings |
} |
return; |
} |
// Action Methods |
// Action method to display the previous month. May wrap to the last month of the last year if there is no previous year. |
- (IBAction)previousMonth:(id)sender |
{ |
[self previousMonth]; |
return; |
} |
// Action method to display the next month. May wrap to the first month of the first year if there is no next year. |
- (IBAction)nextMonth:(id)sender |
{ |
[self nextMonth]; |
return; |
} |
// Model Creation Methods--these methods are used to create the calendar, year, month, and day model objects. |
// Returns an array of years that we are modeling |
- (id)_createCalendarYear:(NSCalendarDate *)year { |
id dict = [self _createYearWithDate:year]; |
[dict setValue:[self _createMonthsOfYear:year] forKey:@"months"]; |
return dict; |
} |
// Returns an array of months for the given year where each month has keys: date, name, weeks |
- (id)_createMonthsOfYear:(NSCalendarDate *)year |
{ |
NSMutableArray *slots = [NSMutableArray array]; |
NSCalendarDate *month = [[year copy] autorelease]; |
int j, y = [month yearOfCommonEra]; |
for (j = y; j == y;){ |
// Create a dictionary representing this month |
id dict = [self _createMonthWithDate:month]; |
[dict setValue:[self _createWeeksOfMonth:month] forKey:@"weeks"]; |
[slots addObject:dict]; |
month = [month dateByAddingYears:0 months:1 days:0 hours:0 minutes:0 seconds:0]; |
j = [month yearOfCommonEra]; |
} |
return slots; |
} |
// Returns an NSArray containing weeks of a month where each week is a dictionary (see daysOfWeek:) |
- (id)_createWeeksOfMonth:(NSCalendarDate *)month |
{ |
NSMutableArray *slots = [NSMutableArray array]; |
NSCalendarDate *week = [[month copy] autorelease]; |
int j, m = [week monthOfYear]; |
for (j = m; j == m;){ |
[slots addObject:[self _createDaysOfWeek:week]]; |
week = [week dateByAddingYears:0 months:0 days:(DaysPerWeek - [week dayOfWeek]) hours:0 minutes:0 seconds:0]; |
j = [week monthOfYear]; |
} |
return slots; |
} |
// Returns a dictionary representation of a week in a month withkeys: Sun, Mon, Tues, Wed, Thurs, Fri, Sat |
- (id)_createDaysOfWeek:(NSCalendarDate *)week |
{ |
NSMutableArray *slots =[NSMutableArray array]; |
NSCalendarDate *day; |
int m = [week monthOfYear]; |
int i, j; |
// Create preceeding month's days to fill out the week |
int firstDayOfWeek = [week dayOfWeek]; |
for (i=0; i < firstDayOfWeek; i++){ |
day = [week dateByAddingYears:0 months:0 days:(i-firstDayOfWeek) hours:0 minutes:0 seconds:0]; |
[slots addObject:day]; |
} |
// Create remaining days |
day = [[week copy] autorelease]; |
for (i = firstDayOfWeek, j = m; (i < DaysPerWeek) && (j == m); i++){ |
[slots addObject:day]; |
day = [day dateByAddingYears:0 months:0 days:1 hours:0 minutes:0 seconds:0]; |
j = [day monthOfYear]; |
} |
// Now you have an array containing the dates in this week to use to create a dictionary representation of the week |
NSMutableDictionary *dict = [NSMutableDictionary dictionary]; |
for (i = 0; i < [slots count]; i++) { |
id value = [self _createDayWithDate:[slots objectAtIndex:i]]; |
id key = [[slots objectAtIndex:i] descriptionWithCalendarFormat:@"%a"]; |
//NSLog(@"day key=%@", key); |
[dict setValue:value forKey:key]; |
} |
// NOTE: You probably want to share the day objects from the previous or preceeding months with the previous |
// or preceeding weeks. Should enhance this later to do so if this causes problems (multiple reps of the same day). |
return dict; |
} |
// Returns a dictionary representation of a year where the year keys are: date, months |
- (id)_createYearWithDate:(NSCalendarDate *)date |
{ |
//NSLog(@"yearWithDate: %@", [date description]); |
NSMutableDictionary *year = [NSMutableDictionary dictionary]; |
[year setValue:date forKey:@"date"]; |
// more keys will be added later |
return year; |
} |
// Returns a dictionary representation of a month where the month keys are: date, name, weeks |
- (id)_createMonthWithDate:(NSCalendarDate *)date |
{ |
//NSLog(@"monthWithDate: %@", [date description]); |
NSMutableDictionary *month = [NSMutableDictionary dictionary]; |
[month setValue:date forKey:@"date"]; |
[month setValue:[date descriptionWithCalendarFormat:@"%B"] forKey:@"name"]; // not necessary, is derived |
// more keys will be added later |
return month; |
} |
// Returns a dictionary representation of a day where day keys are: date, events. Events are added to the day later. |
- (id)_createDayWithDate:(NSCalendarDate *)date |
{ |
//NSLog(@"dayWithDate: %@", [date description]); |
NSMutableDictionary *day = [NSMutableDictionary dictionary]; |
[day setValue:date forKey:@"date"]; |
//[day setValue:[NSMutableArray array] forKey:@"events"]; |
// more keys will be added later |
return day; |
} |
@end |
Copyright © 2006 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2006-07-27