2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include <NGObjWeb/WODynamicElement.h>
25 @class NSMutableArray, NSCalendarDate;
29 @interface WEMonthOverview : WODynamicElement
31 WOAssociation *list; // list of appointments
32 WOAssociation *item; // current item in list
33 WOAssociation *index; // index of current element
34 WOAssociation *identifier; // unique identifier for current item
36 WOAssociation *currentDay; // current day, e.g. 31.Aug, 1.Sep, 2.Sep, ...
38 WOAssociation *year; // year
39 WOAssociation *month; // month
40 WOAssociation *timeZone; // timeZone
42 WOAssociation *firstDay; // 0 - Sunday .. 6 - Saturday (default:1)
43 WOAssociation *tableTags; // make table tags
45 WOAssociation *startDateKey;
46 WOAssociation *endDateKey;
48 WOAssociation *labelStyle; // style sheet classes
49 WOAssociation *contentStyle;
51 WOAssociation *labelColor;
52 WOAssociation *contentColor;
55 NSMutableArray *matrix[MatrixSize];
58 int firstDisplayedDay; // first day to be displayed Sun 0 .. Sat 6
59 int weeks; // number of weeks to display
60 NSCalendarDate *start; // reference date in matrix
64 // extra attributes forwarded to table data
67 @end /* WEMonthOverview */
69 @interface WEMonthLabel : WODynamicElement
71 WOAssociation *orientation;
72 // left/top | top | right/top | right | right/bottom | bottom | left/bottom
74 WOAssociation *dayOfWeek;
75 // set if orientation is top or bottom
76 WOAssociation *weekOfYear;
77 // set if orientation is left or right
78 WOAssociation *colspan;
79 // set if orientation is header
82 @end /* WEMonthLabel */
84 @interface WEMonthTitle : WODynamicElement
88 @end /* WEMonthTitle */
91 #include "WEContextConditional.h"
92 #include <math.h> /* needed for floor() */
95 static NSString *WEMonthOverview_InfoMode = @"WEMonthOverview_InfoMode";
96 static NSString *WEMonthOverview_ContentMode = @"WEMonthOverview_ContentMode";
98 #define SecondsPerDay (24 * 60 * 60)
100 @interface WOContext(WEMonthOverview)
102 - (void)setupMonthOverviewContextWithValue:(id)_value forKey:(NSString *)_key;
103 - (void)setupMonthOverviewContextForQueryMode;
104 - (void)setupMonthOverviewContextWithOrientation:(NSString *)_orient;
106 - (void)tearDownMonthOverviewContext;
107 - (NSDictionary *)monthOverviewContext;
108 - (NSMutableArray *)monthOverviewQueryObjects;
110 - (void)enableMonthOverviewInfoMode;
111 - (void)disableMonthOverviewInfoMode;
112 - (void)enableMonthOverviewContentMode;
113 - (void)disableMonthOverviewContentMode;
117 @implementation WOContext(WEMonthOverview)
119 - (void)setupMonthOverviewContextWithValue:(id)_value forKey:(NSString *)_key {
122 d = [[NSDictionary alloc] initWithObjects:&_value forKeys:&_key count:1];
123 [self setObject:d forKey:@"WEMonthOverview"];
126 - (void)setupMonthOverviewContextForQueryMode {
129 d = [[NSDictionary alloc] initWithObjectsAndKeys:
130 [NSMutableArray arrayWithCapacity:4],
132 [self setObject:d forKey:@"WEMonthOverview"];
135 - (void)setupMonthOverviewContextWithOrientation:(NSString *)_orient {
138 d = [[NSDictionary alloc] initWithObjectsAndKeys:@"--", _orient, nil];
139 [self setObject:d forKey:@"WEMonthOverview"];
143 - (void)tearDownMonthOverviewContext {
144 [self removeObjectForKey:@"WEMonthOverview"];
147 - (NSDictionary *)monthOverviewContext {
148 return [self objectForKey:@"WEMonthOverview"];
150 - (NSArray *)monthOverviewQueryObjects {
151 return [[self monthOverviewContext] valueForKey:@"query"];
154 - (void)enableMonthOverviewInfoMode {
155 [self setObject:@"YES" forKey:WEMonthOverview_InfoMode];
157 - (void)disableMonthOverviewInfoMode {
158 [self removeObjectForKey:WEMonthOverview_InfoMode];
161 - (void)enableMonthOverviewContentMode {
162 [self setObject:@"YES" forKey:WEMonthOverview_ContentMode];
164 - (void)disableMonthOverviewContentMode {
165 [self removeObjectForKey:WEMonthOverview_ContentMode];
168 @end /* WOContext(WEMonthOverview) */
170 @implementation WEMonthOverview
172 static Class StrClass = nil;
175 if (StrClass == Nil) StrClass = [NSString class];
178 static NSString *retStrForInt(int i) {
190 case 10: return @"10";
191 // TODO: find useful count!
193 unsigned char buf[32];
194 sprintf(buf, "%i", i);
195 return [[StrClass alloc] initWithCString:buf];
200 - (id)initWithName:(NSString *)_name
201 associations:(NSDictionary*)_config
202 template:(WOElement *)_t
204 if ((self = [super initWithName:_name associations:_config template:_t])) {
205 self->list = WOExtGetProperty(_config, @"list");
206 self->item = WOExtGetProperty(_config, @"item");
207 self->index = WOExtGetProperty(_config, @"index");
208 self->identifier = WOExtGetProperty(_config, @"identifier");
210 self->currentDay = WOExtGetProperty(_config, @"currentDay");
212 self->year = WOExtGetProperty(_config, @"year");
213 self->month = WOExtGetProperty(_config, @"month");
214 self->timeZone = WOExtGetProperty(_config, @"timeZone");
215 self->firstDay = WOExtGetProperty(_config, @"firstDay");
216 self->tableTags = WOExtGetProperty(_config, @"tableTags");
218 self->startDateKey = WOExtGetProperty(_config, @"startDateKey");
219 self->endDateKey = WOExtGetProperty(_config, @"endDateKey");
221 self->labelStyle = WOExtGetProperty(_config, @"labelStyle");
222 self->contentStyle = WOExtGetProperty(_config, @"contentStyle");
224 self->labelColor = WOExtGetProperty(_config, @"labelColor");
225 self->contentColor = WOExtGetProperty(_config, @"contentColor");
227 if (self->startDateKey == nil) {
229 [[WOAssociation associationWithValue:@"startDate"] retain];
231 if (self->endDateKey == nil) {
233 [[WOAssociation associationWithValue:@"endDate"] retain];
235 self->template = [_t retain];
240 - (void)resetMatrix {
243 for (i=0; i < MatrixSize; i++) {
244 [self->matrix[i] release];
245 self->matrix[i] = nil;
247 [self->matrixInfo.start release]; self->matrixInfo.start = nil;
251 [self->list release];
252 [self->item release];
253 [self->index release];
254 [self->identifier release];
255 [self->currentDay release];
256 [self->year release];
257 [self->month release];
258 [self->timeZone release];
259 [self->firstDay release];
260 [self->tableTags release];
262 [self->startDateKey release];
263 [self->endDateKey release];
264 [self->labelStyle release];
265 [self->contentStyle release];
266 [self->labelColor release];
267 [self->contentColor release];
271 [self->template release];
279 _applyIdentifier(WEMonthOverview *self, WOComponent *comp, NSString *_idx)
285 array = [self->list valueInComponent:comp];
286 count = [array count];
291 /* find subelement for unique id */
293 for (cnt = 0; cnt < count; cnt++) {
297 [self->index setUnsignedIntValue:cnt inComponent:comp];
300 [self->item setValue:[array objectAtIndex:cnt] inComponent:comp];
302 ident = [self->identifier stringValueInComponent:comp];
304 if ([ident isEqualToString:_idx]) {
305 /* found subelement with unique id */
311 @"WEMonthOverview: array did change, "
312 @"unique-id isn't contained."];
313 [self->item setValue:nil inComponent:comp];
314 [self->index setUnsignedIntValue:0 inComponent:comp];
318 _applyIndex(WEMonthOverview *self, WOComponent *comp, unsigned _idx)
323 array = [self->list valueInComponent:comp];
326 [self->index setUnsignedIntValue:_idx inComponent:comp];
328 if (self->item == nil)
331 count = [array count];
334 [self->item setValue:[array objectAtIndex:_idx] inComponent:comp];
339 @"WEMonthOverview: array did change, index is invalid."];
340 [self->item setValue:nil inComponent:comp];
341 [self->index setUnsignedIntValue:0 inComponent:comp];
346 _generateCell(WEMonthOverview *self, WOResponse *response,
347 WOContext *ctx, NSString *key, id value,
348 NSCalendarDate *dateId)
350 [ctx setupMonthOverviewContextWithValue:value forKey:key];
352 [ctx appendElementIDComponent:key];
357 s = retStrForInt([dateId timeIntervalSince1970]);
358 [ctx appendElementIDComponent:s];
362 [self->template appendToResponse:response inContext:ctx];
364 if (dateId) [ctx deleteLastElementIDComponent];
365 [ctx deleteLastElementIDComponent];
366 [ctx tearDownMonthOverviewContext];
370 _takeValuesInCell(WEMonthOverview *self, WORequest *request,
371 WOContext *ctx, NSString *key, id value)
373 [ctx setupMonthOverviewContextWithValue:value forKey:key];
375 [ctx appendElementIDComponent:key];
376 [self->template takeValuesFromRequest:request inContext:ctx];
377 [ctx deleteLastElementIDComponent];
378 // TODO: no teardown of context?
381 - (void)_calcMatrixInContext:(WOContext *)_ctx {
386 int m, y; // month, year
391 comp = [_ctx component];
392 array = [self->list valueInComponent:comp];
393 startKey = [self->startDateKey stringValueInComponent:comp];
394 endKey = [self->endDateKey stringValueInComponent:comp];
396 y = (self->year == nil)
397 ? [[NSCalendarDate calendarDate] yearOfCommonEra]
398 : [self->year intValueInComponent:comp];
400 m = (self->month == nil)
401 ? [[NSCalendarDate calendarDate] monthOfYear]
402 : [self->month intValueInComponent:comp];
406 NSCalendarDate *monthStart = nil;
407 NSCalendarDate *d = nil;
408 NSTimeZone *tz = nil;
409 int firstDisplayedDay, firstIdx;
412 tz = [self->timeZone valueInComponent:comp];
414 monthStart = [NSCalendarDate dateWithYear:y month:m day:1 hour:0 minute:0
415 second:0 timeZone:tz];
417 d = [monthStart dateByAddingYears:0 months:0 days:i];
419 while ([d monthOfYear] == m) {
421 d = [monthStart dateByAddingYears:0 months:0 days:i];
424 firstDisplayedDay = (self->firstDay)
425 ? ([self->firstDay intValueInComponent:comp] % 7)
428 firstIdx = (([monthStart dayOfWeek]-firstDisplayedDay)+7) % 7;
430 self->matrixInfo.weeks = ceil((float)(firstIdx + i) / 7);
431 self->matrixInfo.firstDisplayedDay = firstDisplayedDay;
433 // keep the timezone in the date
434 self->matrixInfo.start =
435 [[monthStart dateByAddingYears:0 months:0 days:-firstIdx] retain];
438 for (i = 0, cnt = [array count]; i < cnt; i++) {
440 NSCalendarDate *sd, *ed;
444 app = [array objectAtIndex:i];
445 sd = [app valueForKey:startKey]; // startDate
446 ed = [app valueForKey:endKey]; // endDate
448 if (sd == nil && ed == nil) continue;
450 diff = [sd timeIntervalSinceDate:self->matrixInfo.start];
452 idx = floor(diff / SecondsPerDay);
454 if (0 <= idx && idx < MatrixSize) {
455 if (self->matrix[idx] == nil)
456 self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
458 [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
460 idx = (idx < 0) ? 0 : idx + 1;
462 diff = [ed timeIntervalSinceDate:self->matrixInfo.start];
463 idx2 = floor(diff / SecondsPerDay);
464 idx2 = (idx2 > MatrixSize) ? MatrixSize : idx2;
467 if (self->matrix[idx] == nil)
468 self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
470 [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
475 for (i = 0; i < MatrixSize; i++) {
476 if (self->matrix[i] == nil)
477 self->matrix[i] = [[NSArray alloc] init];
481 - (void)appendContentToResponse:(WOResponse *)_response
482 inContext:(WOContext *)_ctx
488 int i, cnt, idx, count;
490 comp = [_ctx component];
491 array = [self->list valueInComponent:comp];
492 count = [array count];
494 // *** append day info
495 [_ctx enableMonthOverviewInfoMode];
496 [_ctx appendElementIDComponent:@"i"];
497 [self->template appendToResponse:_response inContext:_ctx];
498 [_ctx deleteLastElementIDComponent];
499 [_ctx disableMonthOverviewInfoMode];
501 // *** append day content
502 [_ctx enableMonthOverviewContentMode];
503 [_ctx appendElementIDComponent:@"c"]; // append content mode
504 for (i = 0, cnt = [self->matrix[_idx] count]; i < cnt; i++) {
507 idx = [[self->matrix[_idx] objectAtIndex:i] intValue];
510 NSLog(@"Warning! WEMonthOverview: index out of range");
513 app = [array objectAtIndex:idx];
515 if ([self->item isValueSettable])
516 [self->item setValue:app inComponent:comp];
517 if ([self->index isValueSettable])
518 [self->index setIntValue:idx inComponent:comp];
520 if (self->identifier == nil) {
521 s = retStrForInt(idx);
522 [_ctx appendElementIDComponent:s];
526 s = [self->identifier stringValueInComponent:comp];
527 [_ctx appendElementIDComponent:s];
530 [self->template appendToResponse:_response inContext:_ctx];
531 [_ctx deleteLastElementIDComponent];
533 [_ctx deleteLastElementIDComponent]; // delete content mode
534 [_ctx disableMonthOverviewContentMode];
537 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
543 BOOL renderDefaults = NO;
546 BOOL hasLeftTop = NO;
549 BOOL hasRightTop = NO;
551 BOOL hasLeftBottom = NO;
553 BOOL hasRightBottom = NO;
556 [self _calcMatrixInContext:_ctx];
558 comp = [_ctx component];
560 useTableTags = (self->tableTags)
561 ? [self->tableTags boolValueInComponent:comp]
564 { // query mode ... testing orientations
565 NSEnumerator *queryE;
568 // only query mode .. no value setting
569 [_ctx setupMonthOverviewContextForQueryMode];
571 /* this walks over all subelements and collects 'query' info */
573 [self->template appendToResponse:_response inContext:_ctx];
575 /* now process the results */
577 queryE = [[_ctx monthOverviewQueryObjects] objectEnumerator];
579 while ((orient = [queryE nextObject])) {
580 if ((!hasHeader) && ([orient isEqualToString:@"header"]))
582 if ((!hasCell) && ([orient isEqualToString:@"cell"]))
584 if ((!hasTitle) && ([orient isEqualToString:@"title"]))
586 if ((!hasLeftTop) && ([orient isEqualToString:@"left/top"]))
588 if ((!hasLeftBottom) && ([orient isEqualToString:@"left/bottom"]))
590 if ((!hasLeft) && ([orient isEqualToString:@"left"]))
592 if ((!hasTop) && ([orient isEqualToString:@"top"]))
594 if ((!hasRightTop) && ([orient isEqualToString:@"right/top"]))
596 if ((!hasRight) && ([orient isEqualToString:@"right"]))
598 if ((!hasRightBottom) && ([orient isEqualToString:@"right/bottom"]))
599 hasRightBottom = YES;
600 if ((!hasBottom) && ([orient isEqualToString:@"bottom"]))
604 if (!(hasLeft || hasRight || hasTop || hasBottom))
605 renderDefaults = YES;
607 [_ctx tearDownMonthOverviewContext];
612 [_response appendContentString:@"<table"];
613 [self appendExtraAttributesToResponse:_response inContext:_ctx];
614 [_response appendContentString:@">"];
617 /* generating head */
622 if ((hasLeft) || (hasLeftTop) || (hasLeftBottom))
624 if ((hasRight) || (hasRightTop) || (hasRightBottom))
627 [_response appendContentString:@"<tr>"];
629 s = retStrForInt(width);
630 _generateCell(self, _response, _ctx, @"header", s, nil);
633 [_response appendContentString:@"</tr>"];
637 if ((hasTop) || (hasLeftTop) || (hasRightTop) || (renderDefaults)) {
638 [_response appendContentString:@"<tr>"];
641 _generateCell(self, _response, _ctx, @"left/top", @"--", nil);
642 else if (hasLeft || hasLeftBottom || renderDefaults)
643 [_response appendContentString:@"<td> </td>"];
648 dow = self->matrixInfo.firstDisplayedDay;
649 for (i = 0; i < 7; i++) {
650 _generateCell(self, _response, _ctx, @"top",
651 [[NSNumber numberWithInt:dow] stringValue], nil);
652 dow = (dow == 6) ? 0 : dow+1;
655 else if (renderDefaults) {
659 day = self->matrixInfo.start;
660 for (i = 0; i < 7; i++) {
663 [_response appendContentString:@"<td align=\"center\""];
664 if ((style = [self->labelStyle stringValueInComponent:comp])) {
665 [_response appendContentString:@" class=\""];
666 [_response appendContentHTMLAttributeValue:style];
667 [_response appendContentCharacter:'"'];
669 if ((bgcolor = [self->labelColor stringValueInComponent:comp])) {
670 [_response appendContentString:@" bgcolor=\""];
671 [_response appendContentString:bgcolor];
672 [_response appendContentCharacter:'"'];
674 [_response appendContentString:@"><b>"];
675 /* TODO: replace with manual string */
676 s = [day descriptionWithCalendarFormat:@"%A"];
677 [_response appendContentString:s];
678 [_response appendContentString:@"</b></td>"];
679 day = [day tomorrow];
682 else if (hasRightTop || hasLeftTop) {
683 [_response appendContentString:
684 @"<td></td><td></td><td></td><td></td>"
685 @"<td></td><td></td><td></td>"];
689 _generateCell(self, _response, _ctx, @"right/top", @"--", nil);
690 else if (hasRightBottom || hasRight)
691 [_response appendContentString:@"<td> </td>"];
693 [_response appendContentString:@"</tr>"];
696 /* generating content */
700 int i, j, maxNumberOfWeeks;
702 day = self->matrixInfo.start;
703 maxNumberOfWeeks = [day numberOfWeeksInYear];
706 retStrForInt([[day dateByAddingYears:0 months:0 days:3] weekOfYear]);
708 for (i = 0; i < self->matrixInfo.weeks; i++) {
709 [_response appendContentString:@"<tr>"];
712 _generateCell(self, _response, _ctx, @"left", week, nil);
714 else if (renderDefaults) {
715 [_response appendContentString:@"<td width=\"2%\" align=\"center\""];
716 if ((style = [self->labelStyle stringValueInComponent:comp])) {
717 [_response appendContentString:@" class=\""];
718 [_response appendContentHTMLAttributeValue:style];
719 [_response appendContentCharacter:'"'];
721 if ((bgcolor = [self->labelColor stringValueInComponent:comp])) {
722 [_response appendContentString:@" bgcolor=\""];
723 [_response appendContentString:bgcolor];
724 [_response appendContentCharacter:'"'];
726 [_response appendContentCharacter:'>'];
727 [_response appendContentString:week];
728 [_response appendContentString:@"</td>"];
730 else if (hasLeftTop || hasLeftBottom)
731 [_response appendContentString:@"<td> </td>"];
733 /* append days of week */
734 for (j = 0; j < 7; j++) {
737 if ([self->currentDay isValueSettable])
738 [self->currentDay setValue:day inComponent:comp];
740 [_response appendContentString:@"<td"];
741 if ((style = [self->contentStyle stringValueInComponent:comp])) {
742 [_response appendContentString:@" class=\""];
743 [_response appendContentHTMLAttributeValue:style];
744 [_response appendContentCharacter:'"'];
746 if ((bgcolor = [self->contentColor stringValueInComponent:comp])) {
747 [_response appendContentString:@" bgcolor=\""];
748 [_response appendContentString:bgcolor];
749 [_response appendContentCharacter:'"'];
751 [_response appendContentCharacter:'>'];
754 [_response appendContentString:
755 @"<table border='0' height='100%' cellspacing='0'"
756 @" cellpadding='2' width='100%'><tr>"];
759 _generateCell(self, _response, _ctx, @"title", @"--", day);
761 [_response appendContentString:
762 @"<td valign=\"top\">"
763 @"<font size=\"4\" color=\"black\">"
765 s = retStrForInt([day dayOfMonth]);
766 [_response appendContentString:s];
768 [_response appendContentString:@"</u></font></td>"];
772 /*** appending content ***/
773 [_ctx appendElementIDComponent:@"cell"];
774 s = retStrForInt([day timeIntervalSince1970]);
775 [_ctx appendElementIDComponent:s];
777 [_response appendContentString:@"<td valign=\"top\">"];
778 [self appendContentToResponse:_response inContext:_ctx index:(i*7+j)];
779 [_response appendContentString:@"</td>"];
780 [_ctx deleteLastElementIDComponent]; // delete date
781 [_ctx deleteLastElementIDComponent]; // delete "cell"
783 [_response appendContentString:@"</tr></table></td>"];
784 day = [day tomorrow];
788 _generateCell(self, _response, _ctx, @"right", week, nil);
789 else if (hasRightTop || hasRightBottom)
790 [_response appendContentString:@"<td> </td>"];
792 [_response appendContentString:@"</tr>"];
796 nextWeek = ([week intValue] % maxNumberOfWeeks) + 1;
797 [week release]; week = nil;
798 week = retStrForInt(nextWeek);
801 [week release]; week = nil;
804 /* generating footer */
805 if ((hasBottom) || (hasLeftBottom) || (hasRightBottom)) {
807 [_response appendContentString:@"<tr>"];
810 _generateCell(self, _response, _ctx, @"left/bottom", @"--", nil);
811 else if (hasLeft || hasLeftTop)
812 [_response appendContentString:@"<td> </td>"];
815 int i, dow = 0; // dayOfWeek
817 dow = self->matrixInfo.firstDisplayedDay;
819 for (i = 0; i < 7; i++) {
822 s = retStrForInt(dow);
823 _generateCell(self, _response, _ctx, @"bottom", s, nil);
825 dow = (dow == 6) ? 0 : dow + 1;
829 [_response appendContentString:
830 @"<td></td><td></td><td></td><td></td>"
831 @"<td></td><td></td><td></td>"];
835 _generateCell(self, _response, _ctx, @"right/bottom", @"--", nil);
836 else if (hasRightTop || hasRight)
837 [_response appendContentString:@"<td> </td>"];
839 [_response appendContentString:@"</tr>"];
844 [_response appendContentString:@"</table>"];
850 - (void)takeContentValues:(WORequest *)_req
851 inContext:(WOContext *)_ctx
857 int i, idx, cnt, count;
859 comp = [_ctx component];
860 array = [self->list valueInComponent:comp];
861 count = [array count];
863 [_ctx appendElementIDComponent:@"c"]; // append content mode
865 cnt = [self->matrix[_idx] count];
866 for (i=0; i<cnt; i++) {
867 idx = [[self->matrix[_idx] objectAtIndex:i] intValue];
870 [self->index setUnsignedIntValue:idx inComponent:comp];
872 [self->item setValue:[array objectAtIndex:idx] inComponent:comp];
874 s = (self->identifier)
875 ? [[self->identifier stringValueInComponent:comp] retain]
878 [_ctx appendElementIDComponent:s]; // append index-id
881 [self->template takeValuesFromRequest:_req inContext:_ctx];
882 [_ctx deleteLastElementIDComponent]; // delte index-id
886 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
887 WOComponent *sComponent;
891 unsigned int weekOfYear;
892 unsigned char buf[32];
894 [self _calcMatrixInContext:_ctx];
896 sComponent = [_ctx component];
898 day = self->matrixInfo.start;
900 weekOfYear = [[day dateByAddingYears:0 months:0 days:3] weekOfYear];
901 sprintf(buf, "%d", weekOfYear);
902 week = [StrClass stringWithCString:buf];
904 // TODO: weird use of NSString for week?
905 for (i = 0; i < self->matrixInfo.weeks; i++) {
906 for (j = 0; j < 7; j++) {
909 if ([self->currentDay isValueSettable])
910 [self->currentDay setValue:day inComponent:sComponent];
912 sprintf(buf, "%d", (unsigned)[day timeIntervalSince1970]);
913 eid = [[StrClass alloc] initWithCString:buf];
914 [_ctx appendElementIDComponent:eid];
917 _takeValuesInCell(self, _req, _ctx, @"title", @"--");
918 [self takeContentValues:_req inContext:_ctx index:(i * 7 + j)];
919 [_ctx deleteLastElementIDComponent];
921 day = [day tomorrow];
923 sprintf(buf, "%d", ([week intValue] + 1));
924 week = [StrClass stringWithCString:buf];
930 - (id)invokeContentAction:(WORequest *)_request inContext:(WOContext *)_ctx{
932 NSString *idxId = nil;
934 if ((idxId = [_ctx currentElementID]) == 0) // no content nor info mode
937 [_ctx consumeElementID]; // consume mode
938 [_ctx appendElementIDComponent:idxId]; // append mode ("c" or "i")
940 if ([idxId isEqualToString:@"i"])
942 result = [self->template invokeActionForRequest:_request inContext:_ctx];
943 else if ((idxId = [_ctx currentElementID])) {
945 [_ctx consumeElementID]; // consume index-id
946 [_ctx appendElementIDComponent:idxId];
948 if (self->identifier)
949 _applyIdentifier(self, [_ctx component], idxId);
951 _applyIndex(self, [_ctx component], [idxId intValue]);
953 result = [self->template invokeActionForRequest:_request inContext:_ctx];
955 [_ctx deleteLastElementIDComponent]; // delete index-id
957 [_ctx deleteLastElementIDComponent]; // delete mode
962 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
963 WOComponent *sComponent;
968 sComponent = [_ctx component];
970 if ((orient = [_ctx currentElementID]) == nil) {
972 logWithFormat:@"%@: MISSING ORIENTATION ID in URL !", self];
976 [_ctx consumeElementID];
977 [_ctx appendElementIDComponent:orient];
979 [_ctx setupMonthOverviewContextWithOrientation:orient];
981 if ([orient isEqualToString:@"cell"] || [orient isEqualToString:@"title"]){
982 /* content or 'title' */
983 if ((ident = [_ctx currentElementID]) != nil) {
987 [_ctx consumeElementID]; // consume date-id
988 [_ctx appendElementIDComponent:ident];
990 ti = [ident intValue];
992 day = [NSCalendarDate dateWithTimeIntervalSince1970:ti];
993 [day setTimeZone:[self->timeZone valueInComponent:sComponent]];
995 if ([self->currentDay isValueSettable])
996 [self->currentDay setValue:day inComponent:sComponent];
998 if ([orient isEqualToString:@"title"])
999 result = [self->template invokeActionForRequest:_req inContext:_ctx];
1001 result = [self invokeContentAction:_req inContext:_ctx];
1003 [_ctx deleteLastElementIDComponent]; // delete 'cell' or 'title'
1007 logWithFormat:@"%@: MISSING DATE ID in '%@' URL !", self, orient];
1010 /* neither 'cell' nor 'title' (some label) */
1011 result = [self->template invokeActionForRequest:_req inContext:_ctx];
1013 [_ctx deleteLastElementIDComponent]; /* delete orient */
1015 // TODO: no teardown of month-overview context?
1020 @end /* WEMonthOverview */
1022 @implementation WEMonthLabel
1024 - (id)initWithName:(NSString *)_name
1025 associations:(NSDictionary*)_config
1026 template:(WOElement *)_t
1028 if ((self = [super initWithName:_name associations:_config template:_t])) {
1029 self->orientation = WOExtGetProperty(_config, @"orientation");
1030 self->dayOfWeek = WOExtGetProperty(_config, @"dayOfWeek");
1031 self->weekOfYear = WOExtGetProperty(_config, @"weekOfYear");
1032 self->colspan = WOExtGetProperty(_config, @"colspan");
1034 self->template = [_t retain];
1040 [self->orientation release];
1041 [self->dayOfWeek release];
1042 [self->weekOfYear release];
1043 [self->colspan release];
1045 [self->template release];
1049 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
1050 NSDictionary *monthViewContextDict;
1055 orient = [self->orientation valueInComponent:[_ctx component]];
1056 isEdge = ([orient rangeOfString:@"/"].length > 0);
1058 monthViewContextDict = [_ctx monthOverviewContext];
1059 if ((tmp = [monthViewContextDict objectForKey:orient]) != nil) {
1061 [_ctx appendElementIDComponent:orient];
1062 [self->template takeValuesFromRequest:_req inContext:_ctx];
1063 [_ctx deleteLastElementIDComponent];
1066 [self->template takeValuesFromRequest:_req inContext:_ctx];
1071 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
1072 NSDictionary *monthViewContextDict;
1078 orient = [self->orientation valueInComponent:[_ctx component]];
1079 isEdge = ([orient rangeOfString:@"/"].length > 0);
1081 monthViewContextDict = [_ctx monthOverviewContext];
1082 if ((tmp = [monthViewContextDict objectForKey:orient]) == nil)
1086 return [self->template invokeActionForRequest:_req inContext:_ctx];
1088 tmp = [_ctx currentElementID];
1089 [_ctx consumeElementID];
1090 [_ctx appendElementIDComponent:tmp];
1092 if ([orient isEqualToString:@"top"] ||
1093 [orient isEqualToString:@"bottom"]) {
1094 [self->dayOfWeek setIntValue:[tmp intValue]
1095 inComponent:[_ctx component]];
1097 else if ([orient isEqualToString:@"left"] ||
1098 [orient isEqualToString:@"right"]) {
1099 [self->weekOfYear setIntValue:[tmp intValue]
1100 inComponent:[_ctx component]];
1102 else if ([orient isEqualToString:@"header"]) {
1103 [self->colspan setIntValue:[tmp intValue]
1104 inComponent:[_ctx component]];
1107 result = [self->template invokeActionForRequest:_req inContext:_ctx];
1109 [_ctx deleteLastElementIDComponent];
1113 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
1114 NSDictionary *monthViewContextDict;
1115 NSMutableArray *queryContext;
1121 orient = [self->orientation stringValueInComponent:[_ctx component]];
1122 isEdge = ([orient rangeOfString:@"/"].length > 0);
1124 if (orient == nil) return;
1126 if ((queryContext = [_ctx monthOverviewQueryObjects]) != nil) {
1127 [queryContext addObject:orient];
1131 monthViewContextDict = [_ctx monthOverviewContext];
1132 if ((tmp = [monthViewContextDict objectForKey:orient]) == nil)
1139 orientIntValue = [tmp intValue];
1140 if ([orient isEqualToString:@"top"] ||
1141 [orient isEqualToString:@"bottom"]) {
1142 [self->dayOfWeek setIntValue:orientIntValue
1143 inComponent:[_ctx component]];
1145 else if ([orient isEqualToString:@"left"] ||
1146 [orient isEqualToString:@"right"]) {
1147 [self->weekOfYear setIntValue:orientIntValue
1148 inComponent:[_ctx component]];
1150 else if ([orient isEqualToString:@"header"]) {
1151 [self->colspan setIntValue:orientIntValue
1152 inComponent:[_ctx component]];
1153 cols = [tmp intValue];
1157 [_response appendContentString:@"<td"];
1162 colStr = retStrForInt(cols);
1163 [_response appendContentString:@" colspan=\""];
1164 [_response appendContentString:colStr];
1165 [_response appendContentString:@"\""];
1169 [self appendExtraAttributesToResponse:_response inContext:_ctx];
1170 [_response appendContentString:@">"];
1173 [_ctx appendElementIDComponent:[tmp stringValue]];
1175 [self->template appendToResponse:_response inContext:_ctx];
1178 [_ctx deleteLastElementIDComponent];
1180 // close table data tag
1181 [_response appendContentString:@"</td>"];
1184 @end /* WEMonthLabel */
1186 @implementation WEMonthTitle
1188 - (id)initWithName:(NSString *)_name
1189 associations:(NSDictionary*)_config
1190 template:(WOElement *)_t
1192 if ((self = [super initWithName:_name associations:_config template:_t])) {
1193 self->template = [_t retain];
1199 [self->template release];
1203 /* handling requests */
1205 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
1206 NSDictionary *monthViewContextDict;
1209 monthViewContextDict = [_ctx monthOverviewContext];
1210 if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil)
1211 [self->template takeValuesFromRequest:_req inContext:_ctx];
1214 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
1215 NSDictionary *monthViewContextDict;
1218 monthViewContextDict = [_ctx monthOverviewContext];
1219 if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil)
1220 return [self->template invokeActionForRequest:_req inContext:_ctx];
1225 /* generating response */
1227 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
1228 NSDictionary *monthViewContextDict;
1231 if ((tmp = [_ctx monthOverviewQueryObjects]) != nil) {
1232 [(NSMutableArray *)tmp addObject:@"title"];
1236 monthViewContextDict = [_ctx monthOverviewContext];
1237 if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil) {
1238 // append table date, forwarding extra attributes
1239 [_response appendContentString:@"<td"];
1240 [self appendExtraAttributesToResponse:_response inContext:_ctx];
1241 [_response appendContentString:@">"];
1243 [self->template appendToResponse:_response inContext:_ctx];
1244 // close table data tag
1245 [_response appendContentString:@"</td>"];
1249 @end /* WEMonthTitle */
1251 @interface WEMonthOverviewInfoMode : WEContextConditional
1254 @implementation WEMonthOverviewInfoMode
1256 - (NSString *)_contextKey {
1257 return WEMonthOverview_InfoMode;
1260 @end /* WEMonthOverviewInfoMode */
1262 @interface WEMonthOverviewContentMode : WEContextConditional
1265 @implementation WEMonthOverviewContentMode
1267 - (NSString *)_contextKey {
1268 return WEMonthOverview_ContentMode;
1271 @end /* WEMonthOverviewContentMode */