2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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 SOPE 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 SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include <NGObjWeb/WODynamicElement.h>
24 @class NSMutableArray, NSCalendarDate;
28 @interface WEMonthOverview : WODynamicElement
30 WOAssociation *list; // list of appointments
31 WOAssociation *item; // current item in list
32 WOAssociation *index; // index of current element
33 WOAssociation *identifier; // unique identifier for current item
35 WOAssociation *currentDay; // current day, e.g. 31.Aug, 1.Sep, 2.Sep, ...
37 WOAssociation *year; // year
38 WOAssociation *month; // month
39 WOAssociation *timeZone; // timeZone
41 WOAssociation *firstDay; // 0 - Sunday .. 6 - Saturday (default:1)
42 WOAssociation *tableTags; // make table tags
44 WOAssociation *startDateKey;
45 WOAssociation *endDateKey;
47 WOAssociation *labelStyle; // style sheet classes
48 WOAssociation *contentStyle;
50 WOAssociation *labelColor;
51 WOAssociation *contentColor;
54 NSMutableArray *matrix[MatrixSize];
57 int firstDisplayedDay; // first day to be displayed Sun 0 .. Sat 6
58 int weeks; // number of weeks to display
59 NSCalendarDate *start; // reference date in matrix
63 // extra attributes forwarded to table data
66 @end /* WEMonthOverview */
68 @interface WEMonthLabel : WODynamicElement
70 WOAssociation *orientation;
71 // left/top | top | right/top | right | right/bottom | bottom | left/bottom
73 WOAssociation *dayOfWeek;
74 // set if orientation is top or bottom
75 WOAssociation *weekOfYear;
76 // set if orientation is left or right
77 WOAssociation *colspan;
78 // set if orientation is header
81 @end /* WEMonthLabel */
83 @interface WEMonthTitle : WODynamicElement
87 @end /* WEMonthTitle */
90 #include "WEContextConditional.h"
91 #include <math.h> /* needed for floor() */
94 static NSString *WEMonthOverview_InfoMode = @"WEMonthOverview_InfoMode";
95 static NSString *WEMonthOverview_ContentMode = @"WEMonthOverview_ContentMode";
97 #define SecondsPerDay (24 * 60 * 60)
99 @interface WOContext(WEMonthOverview)
101 - (void)setupMonthOverviewContextWithValue:(id)_value forKey:(NSString *)_key;
102 - (void)setupMonthOverviewContextForQueryMode;
103 - (void)setupMonthOverviewContextWithOrientation:(NSString *)_orient;
105 - (void)tearDownMonthOverviewContext;
106 - (NSDictionary *)monthOverviewContext;
107 - (NSMutableArray *)monthOverviewQueryObjects;
109 - (void)enableMonthOverviewInfoMode;
110 - (void)disableMonthOverviewInfoMode;
111 - (void)enableMonthOverviewContentMode;
112 - (void)disableMonthOverviewContentMode;
116 @implementation WOContext(WEMonthOverview)
118 - (void)setupMonthOverviewContextWithValue:(id)_value forKey:(NSString *)_key {
121 d = [[NSDictionary alloc] initWithObjects:&_value forKeys:&_key count:1];
122 [self setObject:d forKey:@"WEMonthOverview"];
125 - (void)setupMonthOverviewContextForQueryMode {
128 d = [[NSDictionary alloc] initWithObjectsAndKeys:
129 [NSMutableArray arrayWithCapacity:4],
131 [self setObject:d forKey:@"WEMonthOverview"];
134 - (void)setupMonthOverviewContextWithOrientation:(NSString *)_orient {
137 d = [[NSDictionary alloc] initWithObjectsAndKeys:@"--", _orient, nil];
138 [self setObject:d forKey:@"WEMonthOverview"];
142 - (void)tearDownMonthOverviewContext {
143 [self removeObjectForKey:@"WEMonthOverview"];
146 - (NSDictionary *)monthOverviewContext {
147 return [self objectForKey:@"WEMonthOverview"];
149 - (NSArray *)monthOverviewQueryObjects {
150 return [[self monthOverviewContext] valueForKey:@"query"];
153 - (void)enableMonthOverviewInfoMode {
154 [self setObject:@"YES" forKey:WEMonthOverview_InfoMode];
156 - (void)disableMonthOverviewInfoMode {
157 [self removeObjectForKey:WEMonthOverview_InfoMode];
160 - (void)enableMonthOverviewContentMode {
161 [self setObject:@"YES" forKey:WEMonthOverview_ContentMode];
163 - (void)disableMonthOverviewContentMode {
164 [self removeObjectForKey:WEMonthOverview_ContentMode];
167 @end /* WOContext(WEMonthOverview) */
169 @implementation WEMonthOverview
171 static Class StrClass = nil;
174 if (StrClass == Nil) StrClass = [NSString class];
177 static NSString *retStrForInt(int i) {
189 case 10: return @"10";
190 // TODO: find useful count!
192 unsigned char buf[32];
193 sprintf(buf, "%i", i);
194 return [[StrClass alloc] initWithCString:buf];
199 - (id)initWithName:(NSString *)_name
200 associations:(NSDictionary*)_config
201 template:(WOElement *)_t
203 if ((self = [super initWithName:_name associations:_config template:_t])) {
204 self->list = WOExtGetProperty(_config, @"list");
205 self->item = WOExtGetProperty(_config, @"item");
206 self->index = WOExtGetProperty(_config, @"index");
207 self->identifier = WOExtGetProperty(_config, @"identifier");
209 self->currentDay = WOExtGetProperty(_config, @"currentDay");
211 self->year = WOExtGetProperty(_config, @"year");
212 self->month = WOExtGetProperty(_config, @"month");
213 self->timeZone = WOExtGetProperty(_config, @"timeZone");
214 self->firstDay = WOExtGetProperty(_config, @"firstDay");
215 self->tableTags = WOExtGetProperty(_config, @"tableTags");
217 self->startDateKey = WOExtGetProperty(_config, @"startDateKey");
218 self->endDateKey = WOExtGetProperty(_config, @"endDateKey");
220 self->labelStyle = WOExtGetProperty(_config, @"labelStyle");
221 self->contentStyle = WOExtGetProperty(_config, @"contentStyle");
223 self->labelColor = WOExtGetProperty(_config, @"labelColor");
224 self->contentColor = WOExtGetProperty(_config, @"contentColor");
226 if (self->startDateKey == nil) {
228 [[WOAssociation associationWithValue:@"startDate"] retain];
230 if (self->endDateKey == nil) {
232 [[WOAssociation associationWithValue:@"endDate"] retain];
234 self->template = [_t retain];
239 - (void)resetMatrix {
242 for (i=0; i < MatrixSize; i++) {
243 [self->matrix[i] release];
244 self->matrix[i] = nil;
246 [self->matrixInfo.start release]; self->matrixInfo.start = nil;
250 [self->list release];
251 [self->item release];
252 [self->index release];
253 [self->identifier release];
254 [self->currentDay release];
255 [self->year release];
256 [self->month release];
257 [self->timeZone release];
258 [self->firstDay release];
259 [self->tableTags release];
261 [self->startDateKey release];
262 [self->endDateKey release];
263 [self->labelStyle release];
264 [self->contentStyle release];
265 [self->labelColor release];
266 [self->contentColor release];
270 [self->template release];
278 _applyIdentifier(WEMonthOverview *self, WOComponent *comp, NSString *_idx)
284 array = [self->list valueInComponent:comp];
285 count = [array count];
290 /* find subelement for unique id */
292 for (cnt = 0; cnt < count; cnt++) {
296 [self->index setUnsignedIntValue:cnt inComponent:comp];
299 [self->item setValue:[array objectAtIndex:cnt] inComponent:comp];
301 ident = [self->identifier stringValueInComponent:comp];
303 if ([ident isEqualToString:_idx]) {
304 /* found subelement with unique id */
310 @"WEMonthOverview: array did change, "
311 @"unique-id isn't contained."];
312 [self->item setValue:nil inComponent:comp];
313 [self->index setUnsignedIntValue:0 inComponent:comp];
317 _applyIndex(WEMonthOverview *self, WOComponent *comp, unsigned _idx)
322 array = [self->list valueInComponent:comp];
325 [self->index setUnsignedIntValue:_idx inComponent:comp];
327 if (self->item == nil)
330 count = [array count];
333 [self->item setValue:[array objectAtIndex:_idx] inComponent:comp];
338 @"WEMonthOverview: array did change, index is invalid."];
339 [self->item setValue:nil inComponent:comp];
340 [self->index setUnsignedIntValue:0 inComponent:comp];
345 _generateCell(WEMonthOverview *self, WOResponse *response,
346 WOContext *ctx, NSString *key, id value,
347 NSCalendarDate *dateId)
349 [ctx setupMonthOverviewContextWithValue:value forKey:key];
351 [ctx appendElementIDComponent:key];
356 s = retStrForInt([dateId timeIntervalSince1970]);
357 [ctx appendElementIDComponent:s];
361 [self->template appendToResponse:response inContext:ctx];
363 if (dateId) [ctx deleteLastElementIDComponent];
364 [ctx deleteLastElementIDComponent];
365 [ctx tearDownMonthOverviewContext];
369 _takeValuesInCell(WEMonthOverview *self, WORequest *request,
370 WOContext *ctx, NSString *key, id value)
372 [ctx setupMonthOverviewContextWithValue:value forKey:key];
374 [ctx appendElementIDComponent:key];
375 [self->template takeValuesFromRequest:request inContext:ctx];
376 [ctx deleteLastElementIDComponent];
377 // TODO: no teardown of context?
380 - (void)_calcMatrixInContext:(WOContext *)_ctx {
385 int m, y; // month, year
390 comp = [_ctx component];
391 array = [self->list valueInComponent:comp];
392 startKey = [self->startDateKey stringValueInComponent:comp];
393 endKey = [self->endDateKey stringValueInComponent:comp];
395 y = (self->year == nil)
396 ? [[NSCalendarDate calendarDate] yearOfCommonEra]
397 : [self->year intValueInComponent:comp];
399 m = (self->month == nil)
400 ? [[NSCalendarDate calendarDate] monthOfYear]
401 : [self->month intValueInComponent:comp];
405 NSCalendarDate *monthStart = nil;
406 NSCalendarDate *d = nil;
407 NSTimeZone *tz = nil;
408 int firstDisplayedDay, firstIdx;
411 tz = [self->timeZone valueInComponent:comp];
413 monthStart = [NSCalendarDate dateWithYear:y month:m day:1 hour:0 minute:0
414 second:0 timeZone:tz];
416 d = [monthStart dateByAddingYears:0 months:0 days:i];
418 while ([d monthOfYear] == m) {
420 d = [monthStart dateByAddingYears:0 months:0 days:i];
423 firstDisplayedDay = (self->firstDay)
424 ? ([self->firstDay intValueInComponent:comp] % 7)
427 firstIdx = (([monthStart dayOfWeek]-firstDisplayedDay)+7) % 7;
429 self->matrixInfo.weeks = ceil((float)(firstIdx + i) / 7);
430 self->matrixInfo.firstDisplayedDay = firstDisplayedDay;
432 // keep the timezone in the date
433 self->matrixInfo.start =
434 [[monthStart dateByAddingYears:0 months:0 days:-firstIdx] retain];
437 for (i = 0, cnt = [array count]; i < cnt; i++) {
439 NSCalendarDate *sd, *ed;
443 app = [array objectAtIndex:i];
444 sd = [app valueForKey:startKey]; // startDate
445 ed = [app valueForKey:endKey]; // endDate
447 if (sd == nil && ed == nil) continue;
449 diff = [sd timeIntervalSinceDate:self->matrixInfo.start];
451 idx = floor(diff / SecondsPerDay);
453 if (0 <= idx && idx < MatrixSize) {
454 if (self->matrix[idx] == nil)
455 self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
457 [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
459 idx = (idx < 0) ? 0 : idx + 1;
461 diff = [ed timeIntervalSinceDate:self->matrixInfo.start];
462 idx2 = floor(diff / SecondsPerDay);
463 idx2 = (idx2 > MatrixSize) ? MatrixSize : idx2;
466 if (self->matrix[idx] == nil)
467 self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
469 [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
474 for (i = 0; i < MatrixSize; i++) {
475 if (self->matrix[i] == nil)
476 self->matrix[i] = [[NSArray alloc] init];
480 - (void)appendContentToResponse:(WOResponse *)_response
481 inContext:(WOContext *)_ctx
487 int i, cnt, idx, count;
489 comp = [_ctx component];
490 array = [self->list valueInComponent:comp];
491 count = [array count];
493 // *** append day info
494 [_ctx enableMonthOverviewInfoMode];
495 [_ctx appendElementIDComponent:@"i"];
496 [self->template appendToResponse:_response inContext:_ctx];
497 [_ctx deleteLastElementIDComponent];
498 [_ctx disableMonthOverviewInfoMode];
500 // *** append day content
501 [_ctx enableMonthOverviewContentMode];
502 [_ctx appendElementIDComponent:@"c"]; // append content mode
503 for (i = 0, cnt = [self->matrix[_idx] count]; i < cnt; i++) {
506 idx = [[self->matrix[_idx] objectAtIndex:i] intValue];
509 NSLog(@"Warning! WEMonthOverview: index out of range");
512 app = [array objectAtIndex:idx];
514 if ([self->item isValueSettable])
515 [self->item setValue:app inComponent:comp];
516 if ([self->index isValueSettable])
517 [self->index setIntValue:idx inComponent:comp];
519 if (self->identifier == nil) {
520 s = retStrForInt(idx);
521 [_ctx appendElementIDComponent:s];
525 s = [self->identifier stringValueInComponent:comp];
526 [_ctx appendElementIDComponent:s];
529 [self->template appendToResponse:_response inContext:_ctx];
530 [_ctx deleteLastElementIDComponent];
532 [_ctx deleteLastElementIDComponent]; // delete content mode
533 [_ctx disableMonthOverviewContentMode];
536 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
542 BOOL renderDefaults = NO;
545 BOOL hasLeftTop = NO;
548 BOOL hasRightTop = NO;
550 BOOL hasLeftBottom = NO;
552 BOOL hasRightBottom = NO;
555 [self _calcMatrixInContext:_ctx];
557 comp = [_ctx component];
559 useTableTags = (self->tableTags)
560 ? [self->tableTags boolValueInComponent:comp]
563 { // query mode ... testing orientations
564 NSEnumerator *queryE;
567 // only query mode .. no value setting
568 [_ctx setupMonthOverviewContextForQueryMode];
570 /* this walks over all subelements and collects 'query' info */
572 [self->template appendToResponse:_response inContext:_ctx];
574 /* now process the results */
576 queryE = [[_ctx monthOverviewQueryObjects] objectEnumerator];
578 while ((orient = [queryE nextObject])) {
579 if ((!hasHeader) && ([orient isEqualToString:@"header"]))
581 if ((!hasCell) && ([orient isEqualToString:@"cell"]))
583 if ((!hasTitle) && ([orient isEqualToString:@"title"]))
585 if ((!hasLeftTop) && ([orient isEqualToString:@"left/top"]))
587 if ((!hasLeftBottom) && ([orient isEqualToString:@"left/bottom"]))
589 if ((!hasLeft) && ([orient isEqualToString:@"left"]))
591 if ((!hasTop) && ([orient isEqualToString:@"top"]))
593 if ((!hasRightTop) && ([orient isEqualToString:@"right/top"]))
595 if ((!hasRight) && ([orient isEqualToString:@"right"]))
597 if ((!hasRightBottom) && ([orient isEqualToString:@"right/bottom"]))
598 hasRightBottom = YES;
599 if ((!hasBottom) && ([orient isEqualToString:@"bottom"]))
603 if (!(hasLeft || hasRight || hasTop || hasBottom))
604 renderDefaults = YES;
606 [_ctx tearDownMonthOverviewContext];
611 [_response appendContentString:@"<table"];
612 [self appendExtraAttributesToResponse:_response inContext:_ctx];
613 [_response appendContentString:@">"];
616 /* generating head */
621 if ((hasLeft) || (hasLeftTop) || (hasLeftBottom))
623 if ((hasRight) || (hasRightTop) || (hasRightBottom))
626 [_response appendContentString:@"<tr>"];
628 s = retStrForInt(width);
629 _generateCell(self, _response, _ctx, @"header", s, nil);
632 [_response appendContentString:@"</tr>"];
636 if ((hasTop) || (hasLeftTop) || (hasRightTop) || (renderDefaults)) {
637 [_response appendContentString:@"<tr>"];
640 _generateCell(self, _response, _ctx, @"left/top", @"--", nil);
641 else if (hasLeft || hasLeftBottom || renderDefaults)
642 [_response appendContentString:@"<td> </td>"];
647 dow = self->matrixInfo.firstDisplayedDay;
648 for (i = 0; i < 7; i++) {
649 _generateCell(self, _response, _ctx, @"top",
650 [[NSNumber numberWithInt:dow] stringValue], nil);
651 dow = (dow == 6) ? 0 : dow+1;
654 else if (renderDefaults) {
658 day = self->matrixInfo.start;
659 for (i = 0; i < 7; i++) {
662 [_response appendContentString:@"<td align=\"center\""];
663 if ((style = [self->labelStyle stringValueInComponent:comp])) {
664 [_response appendContentString:@" class=\""];
665 [_response appendContentHTMLAttributeValue:style];
666 [_response appendContentCharacter:'"'];
668 if ((bgcolor = [self->labelColor stringValueInComponent:comp])) {
669 [_response appendContentString:@" bgcolor=\""];
670 [_response appendContentString:bgcolor];
671 [_response appendContentCharacter:'"'];
673 [_response appendContentString:@"><b>"];
674 /* TODO: replace with manual string */
675 s = [day descriptionWithCalendarFormat:@"%A"];
676 [_response appendContentString:s];
677 [_response appendContentString:@"</b></td>"];
678 day = [day tomorrow];
681 else if (hasRightTop || hasLeftTop) {
682 [_response appendContentString:
683 @"<td></td><td></td><td></td><td></td>"
684 @"<td></td><td></td><td></td>"];
688 _generateCell(self, _response, _ctx, @"right/top", @"--", nil);
689 else if (hasRightBottom || hasRight)
690 [_response appendContentString:@"<td> </td>"];
692 [_response appendContentString:@"</tr>"];
695 /* generating content */
699 int i, j, maxNumberOfWeeks;
701 day = self->matrixInfo.start;
702 maxNumberOfWeeks = [day numberOfWeeksInYear];
705 retStrForInt([[day dateByAddingYears:0 months:0 days:3] weekOfYear]);
707 for (i = 0; i < self->matrixInfo.weeks; i++) {
708 [_response appendContentString:@"<tr>"];
711 _generateCell(self, _response, _ctx, @"left", week, nil);
713 else if (renderDefaults) {
714 [_response appendContentString:@"<td width=\"2%\" align=\"center\""];
715 if ((style = [self->labelStyle stringValueInComponent:comp])) {
716 [_response appendContentString:@" class=\""];
717 [_response appendContentHTMLAttributeValue:style];
718 [_response appendContentCharacter:'"'];
720 if ((bgcolor = [self->labelColor stringValueInComponent:comp])) {
721 [_response appendContentString:@" bgcolor=\""];
722 [_response appendContentString:bgcolor];
723 [_response appendContentCharacter:'"'];
725 [_response appendContentCharacter:'>'];
726 [_response appendContentString:week];
727 [_response appendContentString:@"</td>"];
729 else if (hasLeftTop || hasLeftBottom)
730 [_response appendContentString:@"<td> </td>"];
732 /* append days of week */
733 for (j = 0; j < 7; j++) {
736 if ([self->currentDay isValueSettable])
737 [self->currentDay setValue:day inComponent:comp];
739 [_response appendContentString:@"<td"];
740 if ((style = [self->contentStyle stringValueInComponent:comp])) {
741 [_response appendContentString:@" class=\""];
742 [_response appendContentHTMLAttributeValue:style];
743 [_response appendContentCharacter:'"'];
745 if ((bgcolor = [self->contentColor stringValueInComponent:comp])) {
746 [_response appendContentString:@" bgcolor=\""];
747 [_response appendContentString:bgcolor];
748 [_response appendContentCharacter:'"'];
750 [_response appendContentCharacter:'>'];
753 [_response appendContentString:
754 @"<table border='0' height='100%' cellspacing='0'"
755 @" cellpadding='2' width='100%'><tr>"];
758 _generateCell(self, _response, _ctx, @"title", @"--", day);
760 [_response appendContentString:
761 @"<td valign=\"top\">"
762 @"<font size=\"4\" color=\"black\">"
764 s = retStrForInt([day dayOfMonth]);
765 [_response appendContentString:s];
767 [_response appendContentString:@"</u></font></td>"];
771 /*** appending content ***/
772 [_ctx appendElementIDComponent:@"cell"];
773 s = retStrForInt([day timeIntervalSince1970]);
774 [_ctx appendElementIDComponent:s];
776 [_response appendContentString:@"<td valign=\"top\">"];
777 [self appendContentToResponse:_response inContext:_ctx index:(i*7+j)];
778 [_response appendContentString:@"</td>"];
779 [_ctx deleteLastElementIDComponent]; // delete date
780 [_ctx deleteLastElementIDComponent]; // delete "cell"
782 [_response appendContentString:@"</tr></table></td>"];
783 day = [day tomorrow];
787 _generateCell(self, _response, _ctx, @"right", week, nil);
788 else if (hasRightTop || hasRightBottom)
789 [_response appendContentString:@"<td> </td>"];
791 [_response appendContentString:@"</tr>"];
795 nextWeek = ([week intValue] % maxNumberOfWeeks) + 1;
796 [week release]; week = nil;
797 week = retStrForInt(nextWeek);
800 [week release]; week = nil;
803 /* generating footer */
804 if ((hasBottom) || (hasLeftBottom) || (hasRightBottom)) {
806 [_response appendContentString:@"<tr>"];
809 _generateCell(self, _response, _ctx, @"left/bottom", @"--", nil);
810 else if (hasLeft || hasLeftTop)
811 [_response appendContentString:@"<td> </td>"];
814 int i, dow = 0; // dayOfWeek
816 dow = self->matrixInfo.firstDisplayedDay;
818 for (i = 0; i < 7; i++) {
821 s = retStrForInt(dow);
822 _generateCell(self, _response, _ctx, @"bottom", s, nil);
824 dow = (dow == 6) ? 0 : dow + 1;
828 [_response appendContentString:
829 @"<td></td><td></td><td></td><td></td>"
830 @"<td></td><td></td><td></td>"];
834 _generateCell(self, _response, _ctx, @"right/bottom", @"--", nil);
835 else if (hasRightTop || hasRight)
836 [_response appendContentString:@"<td> </td>"];
838 [_response appendContentString:@"</tr>"];
843 [_response appendContentString:@"</table>"];
849 - (void)takeContentValues:(WORequest *)_req
850 inContext:(WOContext *)_ctx
856 int i, idx, cnt, count;
858 comp = [_ctx component];
859 array = [self->list valueInComponent:comp];
860 count = [array count];
862 [_ctx appendElementIDComponent:@"c"]; // append content mode
864 cnt = [self->matrix[_idx] count];
865 for (i=0; i<cnt; i++) {
866 idx = [[self->matrix[_idx] objectAtIndex:i] intValue];
869 [self->index setUnsignedIntValue:idx inComponent:comp];
871 [self->item setValue:[array objectAtIndex:idx] inComponent:comp];
873 s = (self->identifier)
874 ? [[self->identifier stringValueInComponent:comp] retain]
877 [_ctx appendElementIDComponent:s]; // append index-id
880 [self->template takeValuesFromRequest:_req inContext:_ctx];
881 [_ctx deleteLastElementIDComponent]; // delte index-id
885 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
886 WOComponent *sComponent;
890 unsigned int weekOfYear;
891 unsigned char buf[32];
893 [self _calcMatrixInContext:_ctx];
895 sComponent = [_ctx component];
897 day = self->matrixInfo.start;
899 weekOfYear = [[day dateByAddingYears:0 months:0 days:3] weekOfYear];
900 sprintf(buf, "%d", weekOfYear);
901 week = [StrClass stringWithCString:buf];
903 // TODO: weird use of NSString for week?
904 for (i = 0; i < self->matrixInfo.weeks; i++) {
905 for (j = 0; j < 7; j++) {
908 if ([self->currentDay isValueSettable])
909 [self->currentDay setValue:day inComponent:sComponent];
911 sprintf(buf, "%d", (unsigned)[day timeIntervalSince1970]);
912 eid = [[StrClass alloc] initWithCString:buf];
913 [_ctx appendElementIDComponent:eid];
916 _takeValuesInCell(self, _req, _ctx, @"title", @"--");
917 [self takeContentValues:_req inContext:_ctx index:(i * 7 + j)];
918 [_ctx deleteLastElementIDComponent];
920 day = [day tomorrow];
922 sprintf(buf, "%d", ([week intValue] + 1));
923 week = [StrClass stringWithCString:buf];
929 - (id)invokeContentAction:(WORequest *)_request inContext:(WOContext *)_ctx{
931 NSString *idxId = nil;
933 if ((idxId = [_ctx currentElementID]) == 0) // no content nor info mode
936 [_ctx consumeElementID]; // consume mode
937 [_ctx appendElementIDComponent:idxId]; // append mode ("c" or "i")
939 if ([idxId isEqualToString:@"i"])
941 result = [self->template invokeActionForRequest:_request inContext:_ctx];
942 else if ((idxId = [_ctx currentElementID])) {
944 [_ctx consumeElementID]; // consume index-id
945 [_ctx appendElementIDComponent:idxId];
947 if (self->identifier)
948 _applyIdentifier(self, [_ctx component], idxId);
950 _applyIndex(self, [_ctx component], [idxId intValue]);
952 result = [self->template invokeActionForRequest:_request inContext:_ctx];
954 [_ctx deleteLastElementIDComponent]; // delete index-id
956 [_ctx deleteLastElementIDComponent]; // delete mode
961 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
962 WOComponent *sComponent;
967 sComponent = [_ctx component];
969 if ((orient = [_ctx currentElementID]) == nil) {
971 logWithFormat:@"%@: MISSING ORIENTATION ID in URL !", self];
975 [_ctx consumeElementID];
976 [_ctx appendElementIDComponent:orient];
978 [_ctx setupMonthOverviewContextWithOrientation:orient];
980 if ([orient isEqualToString:@"cell"] || [orient isEqualToString:@"title"]){
981 /* content or 'title' */
982 if ((ident = [_ctx currentElementID]) != nil) {
986 [_ctx consumeElementID]; // consume date-id
987 [_ctx appendElementIDComponent:ident];
989 ti = [ident intValue];
991 day = [NSCalendarDate dateWithTimeIntervalSince1970:ti];
992 [day setTimeZone:[self->timeZone valueInComponent:sComponent]];
994 if ([self->currentDay isValueSettable])
995 [self->currentDay setValue:day inComponent:sComponent];
997 if ([orient isEqualToString:@"title"])
998 result = [self->template invokeActionForRequest:_req inContext:_ctx];
1000 result = [self invokeContentAction:_req inContext:_ctx];
1002 [_ctx deleteLastElementIDComponent]; // delete 'cell' or 'title'
1006 logWithFormat:@"%@: MISSING DATE ID in '%@' URL !", self, orient];
1009 /* neither 'cell' nor 'title' (some label) */
1010 result = [self->template invokeActionForRequest:_req inContext:_ctx];
1012 [_ctx deleteLastElementIDComponent]; /* delete orient */
1014 // TODO: no teardown of month-overview context?
1019 @end /* WEMonthOverview */
1021 @implementation WEMonthLabel
1023 - (id)initWithName:(NSString *)_name
1024 associations:(NSDictionary*)_config
1025 template:(WOElement *)_t
1027 if ((self = [super initWithName:_name associations:_config template:_t])) {
1028 self->orientation = WOExtGetProperty(_config, @"orientation");
1029 self->dayOfWeek = WOExtGetProperty(_config, @"dayOfWeek");
1030 self->weekOfYear = WOExtGetProperty(_config, @"weekOfYear");
1031 self->colspan = WOExtGetProperty(_config, @"colspan");
1033 self->template = [_t retain];
1039 [self->orientation release];
1040 [self->dayOfWeek release];
1041 [self->weekOfYear release];
1042 [self->colspan release];
1044 [self->template release];
1048 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
1049 NSDictionary *monthViewContextDict;
1054 orient = [self->orientation valueInComponent:[_ctx component]];
1055 isEdge = ([orient rangeOfString:@"/"].length > 0);
1057 monthViewContextDict = [_ctx monthOverviewContext];
1058 if ((tmp = [monthViewContextDict objectForKey:orient]) != nil) {
1060 [_ctx appendElementIDComponent:orient];
1061 [self->template takeValuesFromRequest:_req inContext:_ctx];
1062 [_ctx deleteLastElementIDComponent];
1065 [self->template takeValuesFromRequest:_req inContext:_ctx];
1070 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
1071 NSDictionary *monthViewContextDict;
1077 orient = [self->orientation valueInComponent:[_ctx component]];
1078 isEdge = ([orient rangeOfString:@"/"].length > 0);
1080 monthViewContextDict = [_ctx monthOverviewContext];
1081 if ((tmp = [monthViewContextDict objectForKey:orient]) == nil)
1085 return [self->template invokeActionForRequest:_req inContext:_ctx];
1087 tmp = [_ctx currentElementID];
1088 [_ctx consumeElementID];
1089 [_ctx appendElementIDComponent:tmp];
1091 if ([orient isEqualToString:@"top"] ||
1092 [orient isEqualToString:@"bottom"]) {
1093 [self->dayOfWeek setIntValue:[tmp intValue]
1094 inComponent:[_ctx component]];
1096 else if ([orient isEqualToString:@"left"] ||
1097 [orient isEqualToString:@"right"]) {
1098 [self->weekOfYear setIntValue:[tmp intValue]
1099 inComponent:[_ctx component]];
1101 else if ([orient isEqualToString:@"header"]) {
1102 [self->colspan setIntValue:[tmp intValue]
1103 inComponent:[_ctx component]];
1106 result = [self->template invokeActionForRequest:_req inContext:_ctx];
1108 [_ctx deleteLastElementIDComponent];
1112 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
1113 NSDictionary *monthViewContextDict;
1114 NSMutableArray *queryContext;
1120 orient = [self->orientation stringValueInComponent:[_ctx component]];
1121 isEdge = ([orient rangeOfString:@"/"].length > 0);
1123 if (orient == nil) return;
1125 if ((queryContext = [_ctx monthOverviewQueryObjects]) != nil) {
1126 [queryContext addObject:orient];
1130 monthViewContextDict = [_ctx monthOverviewContext];
1131 if ((tmp = [monthViewContextDict objectForKey:orient]) == nil)
1138 orientIntValue = [tmp intValue];
1139 if ([orient isEqualToString:@"top"] ||
1140 [orient isEqualToString:@"bottom"]) {
1141 [self->dayOfWeek setIntValue:orientIntValue
1142 inComponent:[_ctx component]];
1144 else if ([orient isEqualToString:@"left"] ||
1145 [orient isEqualToString:@"right"]) {
1146 [self->weekOfYear setIntValue:orientIntValue
1147 inComponent:[_ctx component]];
1149 else if ([orient isEqualToString:@"header"]) {
1150 [self->colspan setIntValue:orientIntValue
1151 inComponent:[_ctx component]];
1152 cols = [tmp intValue];
1156 [_response appendContentString:@"<td"];
1161 colStr = retStrForInt(cols);
1162 [_response appendContentString:@" colspan=\""];
1163 [_response appendContentString:colStr];
1164 [_response appendContentString:@"\""];
1168 [self appendExtraAttributesToResponse:_response inContext:_ctx];
1169 [_response appendContentString:@">"];
1172 [_ctx appendElementIDComponent:[tmp stringValue]];
1174 [self->template appendToResponse:_response inContext:_ctx];
1177 [_ctx deleteLastElementIDComponent];
1179 // close table data tag
1180 [_response appendContentString:@"</td>"];
1183 @end /* WEMonthLabel */
1185 @implementation WEMonthTitle
1187 - (id)initWithName:(NSString *)_name
1188 associations:(NSDictionary*)_config
1189 template:(WOElement *)_t
1191 if ((self = [super initWithName:_name associations:_config template:_t])) {
1192 self->template = [_t retain];
1198 [self->template release];
1202 /* handling requests */
1204 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
1205 NSDictionary *monthViewContextDict;
1208 monthViewContextDict = [_ctx monthOverviewContext];
1209 if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil)
1210 [self->template takeValuesFromRequest:_req inContext:_ctx];
1213 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
1214 NSDictionary *monthViewContextDict;
1217 monthViewContextDict = [_ctx monthOverviewContext];
1218 if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil)
1219 return [self->template invokeActionForRequest:_req inContext:_ctx];
1224 /* generating response */
1226 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
1227 NSDictionary *monthViewContextDict;
1230 if ((tmp = [_ctx monthOverviewQueryObjects]) != nil) {
1231 [(NSMutableArray *)tmp addObject:@"title"];
1235 monthViewContextDict = [_ctx monthOverviewContext];
1236 if ((tmp = [monthViewContextDict objectForKey:@"title"]) != nil) {
1237 // append table date, forwarding extra attributes
1238 [_response appendContentString:@"<td"];
1239 [self appendExtraAttributesToResponse:_response inContext:_ctx];
1240 [_response appendContentString:@">"];
1242 [self->template appendToResponse:_response inContext:_ctx];
1243 // close table data tag
1244 [_response appendContentString:@"</td>"];
1248 @end /* WEMonthTitle */
1250 @interface WEMonthOverviewInfoMode : WEContextConditional
1253 @implementation WEMonthOverviewInfoMode
1255 - (NSString *)_contextKey {
1256 return WEMonthOverview_InfoMode;
1259 @end /* WEMonthOverviewInfoMode */
1261 @interface WEMonthOverviewContentMode : WEContextConditional
1264 @implementation WEMonthOverviewContentMode
1266 - (NSString *)_contextKey {
1267 return WEMonthOverview_ContentMode;
1270 @end /* WEMonthOverviewContentMode */