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 "WEContextConditional.h"
23 #include <NGObjWeb/WODynamicElement.h>
28 |---------------|---------------|
29 |Mo <content> | Do <content> |
32 |---------------|---------------|
33 |Di <content> | Fr <content> |
36 |---------------|---------------|
37 |Mi <content> | Sa <content> |
40 |---------------|---------------|
43 #define SecondsPerWeek (7 * 24 * 60 * 60)
44 #define SecondsPerDay (24 * 60 * 60)
45 #define MatrixSections 7
47 @class NSMutableArray;
50 #define WEWeekColumnView_TitleMode @"WEWeekColumnView_TitleMode"
51 #define WEWeekColumnView_TitleModeDidMatch @"WEWeekColumnView_TitleModeMatched"
52 #define WEWeekColumnView_InfoMode @"WEWeekColumnView_InfoMode"
53 #define WEWeekColumnView_ContentMode @"WEWeekColumnView_ContentMode"
55 @interface WEWeekColumnView : WODynamicElement
61 WOAssociation *identifier;
63 WOAssociation *dayIndex;
64 WOAssociation *weekStart;
66 WOAssociation *startDateKey;
67 WOAssociation *endDateKey;
69 WOAssociation *titleColor;
70 WOAssociation *contentColor;
72 WOAssociation *isInfoItem; // is current item info entry
73 WOAssociation *infoItems; // current info entries
75 WOAssociation *hideWeekend; /* should Sa/So be rendered? */
78 NSMutableArray *matrix[MatrixSections];
79 NSMutableArray *infos[MatrixSections];
86 #include <math.h> /* Needed for floor() */
89 @implementation WEWeekColumnView
91 static Class StrClass = Nil;
94 StrClass = [NSString class];
97 static NSString *retStrForInt(int i) {
109 case 10: return @"10";
110 // TODO: find useful count!
112 return [[StrClass alloc] initWithFormat:@"%i", i];
116 - (id)initWithName:(NSString *)_name
117 associations:(NSDictionary *)_config
118 template:(WOElement *)_tmp
120 if ((self = [super initWithName:_name associations:_config template:_tmp])) {
121 self->list = WOExtGetProperty(_config, @"list");
122 self->item = WOExtGetProperty(_config, @"item");
123 self->index = WOExtGetProperty(_config, @"index");
124 self->identifier = WOExtGetProperty(_config, @"identifier");
125 self->dayIndex = WOExtGetProperty(_config, @"dayIndex");
126 self->weekStart = WOExtGetProperty(_config, @"weekStart");
127 self->startDateKey = WOExtGetProperty(_config, @"startDateKey");
128 self->endDateKey = WOExtGetProperty(_config, @"endDateKey");
130 self->titleColor = WOExtGetProperty(_config, @"titleColor");
131 self->contentColor = WOExtGetProperty(_config, @"contentColor");
133 self->hideWeekend = WOExtGetProperty(_config, @"hideWeekend");
135 if (self->startDateKey == nil) {
137 [[WOAssociation associationWithValue:@"startDate"] retain];
139 if (self->endDateKey == nil) {
141 [[WOAssociation associationWithValue:@"endDate"] retain];
144 self->isInfoItem = WOExtGetProperty(_config, @"isInfoItem");
145 self->infoItems = WOExtGetProperty(_config, @"infoItems");
147 ASSIGN(self->template, _tmp);
152 - (void)resetMatrix {
155 for (i=0; i<MatrixSections; i++) {
156 [self->matrix[i] release]; self->matrix[i] = nil;
157 [self->infos[i] release]; self->infos[i] = nil;
162 [self->hideWeekend release];
163 [self->list release];
164 [self->item release];
165 [self->index release];
166 [self->identifier release];
167 [self->dayIndex release];
168 [self->weekStart release];
169 [self->startDateKey release];
170 [self->endDateKey release];
171 [self->titleColor release];
172 [self->contentColor release];
173 [self->infoItems release];
174 [self->isInfoItem release];
177 [self->template release];
182 _applyIdentifier(WEWeekColumnView *self, WOComponent *comp, NSString *_idx)
187 array = [self->list valueInComponent:comp];
188 count = [array count];
193 /* find subelement for unique id */
195 for (cnt = 0; cnt < count; cnt++) {
199 [self->index setUnsignedIntValue:cnt inComponent:comp];
202 [self->item setValue:[array objectAtIndex:cnt] inComponent:comp];
204 ident = [self->identifier stringValueInComponent:comp];
206 if ([ident isEqualToString:_idx]) {
207 /* found subelement with unique id */
213 @"WEWeekColumnView: array did change, "
214 @"unique-id isn't contained."];
215 [self->item setValue:nil inComponent:comp];
216 [self->index setUnsignedIntValue:0 inComponent:comp];
220 _applyIndex(WEWeekColumnView *self, WOComponent *comp, unsigned _idx)
225 array = [self->list valueInComponent:comp];
228 [self->index setUnsignedIntValue:_idx inComponent:comp];
230 if (self->item == nil)
233 count = [array count];
235 [self->item setValue:[array objectAtIndex:_idx] inComponent:comp];
240 @"WEWeekColumnView: array did change, index is invalid."];
241 [self->item setValue:nil inComponent:comp];
242 [self->index setUnsignedIntValue:0 inComponent:comp];
245 - (void)_calcMatrixInContext:(WOContext *)_ctx {
247 NSCalendarDate *startWeek;
251 int i, idx, idx2, cnt;
255 [_ctx removeObjectForKey:WEWeekColumnView_TitleModeDidMatch];
256 [_ctx setObject:@"YES" forKey:WEWeekColumnView_TitleMode];
257 [self->template appendToResponse:nil inContext:_ctx];
258 [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
260 if ([_ctx objectForKey:WEWeekColumnView_TitleModeDidMatch] != nil)
261 self->hasOwnTitle = YES;
263 self->hasOwnTitle = NO;
265 comp = [_ctx component];
266 array = [self->list valueInComponent:comp];
267 startKey = [self->startDateKey stringValueInComponent:comp];
268 endKey = [self->endDateKey stringValueInComponent:comp];
269 startWeek = (self->weekStart)
270 ? [self->weekStart valueInComponent:comp]
271 : [NSCalendarDate calendarDate];
273 for (i = 0, cnt = [array count]; i < cnt; i++) {
275 NSCalendarDate *sd, *ed;
279 app = [array objectAtIndex:i];
280 sd = [app valueForKey:startKey]; // startDate
281 ed = [app valueForKey:endKey]; // endDate
283 if ((sd == nil) && (ed == nil)) continue;
285 if ((sd != nil) && (ed != nil) && [ed isEqual:[sd earlierDate:ed]]) {
293 diff = [(sd ? sd : ed) timeIntervalSinceDate:startWeek];
295 idx = floor((diff / SecondsPerWeek) * MatrixSections);
297 if ((self->item) && (self->isInfoItem)) {
298 [self->item setValue:app inComponent:comp];
299 isInfo = [[self->isInfoItem valueInComponent:comp] boolValue];
303 if ((0 <= idx) && (idx < MatrixSections)) {
305 if (self->infos[idx] == nil)
306 self->infos[idx] = [[NSMutableArray alloc] initWithCapacity:2];
307 [self->infos[idx] addObject:[NSNumber numberWithInt:i]];
310 if (self->matrix[idx] == nil)
311 self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
312 [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
315 idx = (idx >= 0) ? idx+1 : idx;
316 diff = [ed timeIntervalSinceDate:startWeek];
318 idx2 = floor((diff / SecondsPerWeek) * MatrixSections);
319 idx2 = (idx2 >= MatrixSections) ? (MatrixSections - 1) : idx2;
321 if (idx2 < 0) continue;
323 while (idx <= idx2) {
324 idx = (idx < 0) ? 0 : idx;
326 if (self->infos[idx] == nil)
327 self->infos[idx] = [[NSMutableArray alloc] initWithCapacity:2];
328 [self->infos[idx] addObject:[NSNumber numberWithInt:i]];
331 if (self->matrix[idx] == nil)
332 self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
333 [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
340 - (void)appendDateTitleToResponse:(WOResponse *)_response
341 inContext:(WOContext *)_ctx
347 comp = [_ctx component];
349 bgcolor = [self->titleColor stringValueInComponent:comp];
351 if ([self->dayIndex isValueSettable])
352 [self->dayIndex setIntValue:_day inComponent:comp];
354 [_response appendContentString:@"<td valign='top' align='left' width='50%'"];
356 [_response appendContentString:@" bgcolor=\""];
357 [_response appendContentString:bgcolor];
358 [_response appendContentCharacter:'"'];
360 [_response appendContentCharacter:'>'];
362 if (self->hasOwnTitle) {
365 [_ctx setObject:@"YES" forKey:WEWeekColumnView_TitleMode];
367 [_ctx appendElementIDComponent:@"t"];
368 s = retStrForInt(_day);
369 [_ctx appendElementIDComponent:s];
372 [self->template appendToResponse:_response inContext:_ctx];
374 [_ctx deleteLastElementIDComponent]; // delete day index
375 [_ctx deleteLastElementIDComponent]; // delete "t"
377 [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
380 NSCalendarDate *date;
382 date = (self->weekStart)
383 ? [self->weekStart valueInComponent:comp]
384 : [NSCalendarDate calendarDate];
385 date = [date addTimeInterval:_day * SecondsPerDay];
387 [_response appendContentString:
388 @"<table cellpadding=0 width=100% border=0 cellspacing=0>"
390 @"<td align=left valign=top>"
391 @"<font color=\"black\" size=\"+2\"><b>"];
393 [_response appendContentString:[date descriptionWithCalendarFormat:@"%d"]];
395 [_response appendContentString:
397 @"<td align=\"center\" valign=\"top\">"
398 @"<font color=\"black\">"];
400 [_response appendContentString:[date descriptionWithCalendarFormat:@"%A"]];
401 [_response appendContentString:
407 [_response appendContentString:@"</td>"];
410 - (void)appendContentToResponse:(WOResponse *)_response
411 inContext:(WOContext *)_ctx
418 int i, cnt, idx, count;
420 comp = [_ctx component];
421 array = [self->list valueInComponent:comp];
422 count = [array count];
424 if ([self->infoItems isValueSettable]) {
425 if ((cnt = [self->infos[_day] count])) {
426 NSMutableArray *infoArr;
428 infoArr = [NSMutableArray arrayWithCapacity:cnt];
429 for (i = 0; i < cnt; i++) {
430 idx = [[self->infos[_day] objectAtIndex:i] intValue];
434 @"WARNING: WEWeekOverview: info index out of range"];
437 [infoArr addObject:[array objectAtIndex:idx]];
439 [self->infoItems setValue:infoArr inComponent:comp];
442 [self->infoItems setValue:[NSArray array] inComponent:comp];
446 // *** append day info
447 [_ctx setObject:@"YES" forKey:WEWeekColumnView_InfoMode];
448 [_ctx appendElementIDComponent:@"i"];
449 s = retStrForInt(_day);
450 [_ctx appendElementIDComponent:s];
452 [self->template appendToResponse:_response inContext:_ctx];
453 [_ctx deleteLastElementIDComponent]; // delete day
454 [_ctx deleteLastElementIDComponent]; // delete "i"
455 [_ctx removeObjectForKey:WEWeekColumnView_InfoMode];
457 // *** append day content
458 [_ctx appendElementIDComponent:@"c"];
459 s = retStrForInt(_day);
460 [_ctx appendElementIDComponent:s];
463 [_ctx setObject:@"YES" forKey:WEWeekColumnView_ContentMode];
465 for (i = 0, cnt = [self->matrix[_day] count]; i < cnt; i++) {
466 idx = [[self->matrix[_day] objectAtIndex:i] intValue];
469 NSLog(@"Warning! WEWeekColumnView: index out of range");
472 app = [array objectAtIndex:idx];
474 if ([self->item isValueSettable])
475 [self->item setValue:app inComponent:comp];
476 if ([self->index isValueSettable])
477 [self->index setIntValue:idx inComponent:comp];
479 if (self->identifier == nil) {
480 s = retStrForInt(idx);
481 [_ctx appendElementIDComponent:s];
487 s = [self->identifier stringValueInComponent:comp];
488 [_ctx appendElementIDComponent:s];
490 [self->template appendToResponse:_response inContext:_ctx];
491 [_ctx deleteLastElementIDComponent];
494 [_response appendContentString:@" "];
495 [_ctx removeObjectForKey:WEWeekColumnView_ContentMode];
497 [_ctx deleteLastElementIDComponent]; // delete day index
498 [_ctx deleteLastElementIDComponent]; // delete "c"
501 /* handling requests */
503 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
508 comp = [_ctx component];
509 array = [self->list valueInComponent:comp];
510 count = [array count];
513 [_ctx setObject:@"YES" forKey:WEWeekColumnView_TitleMode];
514 [_ctx appendElementIDComponent:@"t"]; // append title mode
515 [_ctx appendZeroElementIDComponent]; // append first day (monday)
516 for (i = 0; i < 7; i++) {
517 if ([self->dayIndex isValueSettable])
518 [self->dayIndex setIntValue:i inComponent:comp];
519 [self->template takeValuesFromRequest:_req inContext:_ctx];
520 [_ctx incrementLastElementIDComponent]; // increment day
522 [_ctx deleteLastElementIDComponent]; // delete day
523 [_ctx deleteLastElementIDComponent]; // delete title mode
524 [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
527 [_ctx setObject:@"YES" forKey:WEWeekColumnView_InfoMode];
528 [_ctx appendElementIDComponent:@"i"]; // append info mode
529 [_ctx appendZeroElementIDComponent]; // append day
530 for (i=0; i< 7; i++) {
531 if ([self->dayIndex isValueSettable])
532 [self->dayIndex setIntValue:i inComponent:comp];
534 [self->template takeValuesFromRequest:_req inContext:_ctx];
536 [_ctx incrementLastElementIDComponent]; // increment day
537 [_ctx incrementLastElementIDComponent]; // in steps of 2
539 [_ctx deleteLastElementIDComponent]; // delete day
540 [_ctx deleteLastElementIDComponent]; // delete info mode
541 [_ctx removeObjectForKey:WEWeekColumnView_InfoMode];
544 [self _calcMatrixInContext:_ctx];
546 [_ctx setObject:@"YES" forKey:WEWeekColumnView_ContentMode];
547 [_ctx appendElementIDComponent:@"c"]; // append content mode
548 [_ctx appendZeroElementIDComponent]; // append day-id
549 for (i = 0; i < 7; i++) {
552 cnt = [self->matrix[i] count];
554 if ([self->dayIndex isValueSettable])
555 [self->dayIndex setIntValue:i inComponent:comp];
557 for (j = 0; j < cnt; j++) {
558 idx = [[self->matrix[i] objectAtIndex:j] intValue];
561 NSLog(@"Warning! WEWeekColumnView: Index is out of range");
565 _applyIndex(self, comp, idx);
567 if (self->identifier) {
570 s = [self->identifier stringValueInComponent:comp];
571 [_ctx appendElementIDComponent:s];
576 s = retStrForInt(idx);
577 [_ctx appendElementIDComponent:s];
581 [self->template takeValuesFromRequest:_req inContext:_ctx];
583 [_ctx deleteLastElementIDComponent]; // delete index-id
585 [_ctx incrementLastElementIDComponent]; // increase day-id
587 [_ctx deleteLastElementIDComponent]; // delete day-id
588 [_ctx deleteLastElementIDComponent]; // delete content mode
589 [_ctx removeObjectForKey:WEWeekColumnView_ContentMode];
594 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
600 cid = [_ctx currentElementID]; // get mode ("t" or "i" or "c")
601 [_ctx consumeElementID];
602 [_ctx appendElementIDComponent:cid];
603 dayId = [_ctx currentElementID]; // get day
604 [_ctx consumeElementID];
605 [_ctx appendElementIDComponent:dayId];
607 comp = [_ctx component];
609 if ([cid isEqualToString:@"t"]) {
610 if ([self->dayIndex isValueSettable])
611 [self->dayIndex setIntValue:[dayId intValue] inComponent:comp];
612 result = [self->template invokeActionForRequest:_req inContext:_ctx];
614 else if ([cid isEqualToString:@"i"]) {
615 if ([self->dayIndex isValueSettable])
616 [self->dayIndex setIntValue:[dayId intValue] inComponent:comp];
617 result = [self->template invokeActionForRequest:_req inContext:_ctx];
619 else if ([cid isEqualToString:@"c"]) {
622 if ([self->dayIndex isValueSettable])
623 [self->dayIndex setIntValue:[dayId intValue] inComponent:comp];
625 if ((idxId = [_ctx currentElementID])) {
626 [_ctx consumeElementID]; // consume index-id
627 [_ctx appendElementIDComponent:idxId];
629 if (self->identifier)
630 _applyIdentifier(self, comp, idxId);
632 _applyIndex(self, comp, [idxId intValue]);
634 result = [self->template invokeActionForRequest:_req inContext:_ctx];
636 [_ctx deleteLastElementIDComponent]; // delete index-id
640 [self logWithFormat:@"WARNING! WEWeekColumnView: wrong section"];
642 [_ctx deleteLastElementIDComponent]; // delete section id
643 [_ctx deleteLastElementIDComponent]; // delete mode
648 /* generating response */
650 - (void)appendBgColor:(WOResponse *)_response
651 inContext:(WOContext *)_ctx
656 if ([self->dayIndex isValueSettable])
657 [self->dayIndex setIntValue:_day inComponent:[_ctx component]];
659 if ((bg = [self->contentColor stringValueInComponent:[_ctx component]])) {
660 [_response appendContentString:@" bgcolor=\""];
661 [_response appendContentString:bg];
662 [_response appendContentCharacter:'"'];
666 - (void)appendFirstRowToResponse:(WOResponse *)_response
667 inContext:(WOContext *)_ctx
669 /* first row (Mo,Do) */
670 [_response appendContentString:@"<tr>"];
671 [self appendDateTitleToResponse:_response inContext:_ctx day:0];
672 [self appendDateTitleToResponse:_response inContext:_ctx day:3];
673 [_response appendContentString:@"</tr>"];
675 [_response appendContentString:@"<tr>"];
677 [_response appendContentString:@"<td valign=\"top\""];
678 [self appendBgColor:_response inContext:_ctx day:0];
679 [_response appendContentCharacter:'>'];
681 [self appendContentToResponse:_response inContext:_ctx day:0];
682 [_response appendContentString:@"</td>"];
684 [_response appendContentString:@"<td valign=\"top\""];
685 [self appendBgColor:_response inContext:_ctx day:3];
686 [_response appendContentCharacter:'>'];
688 [self appendContentToResponse:_response inContext:_ctx day:3];
689 [_response appendContentString:@"</td>"];
690 [_response appendContentString:@"</tr>"];
693 - (void)appendSecondRowToResponse:(WOResponse *)_response
694 inContext:(WOContext *)_ctx
696 /* second row (Di,Fr) */
697 [_response appendContentString:@"<tr>"];
698 [self appendDateTitleToResponse:_response inContext:_ctx day:1];
699 [self appendDateTitleToResponse:_response inContext:_ctx day:4];
700 [_response appendContentString:@"</tr>"];
702 [_response appendContentString:@"<tr>"];
704 [_response appendContentString:@"<td valign=\"top\""];
705 [self appendBgColor:_response inContext:_ctx day:1];
706 [_response appendContentCharacter:'>'];
708 [self appendContentToResponse:_response inContext:_ctx day:1];
709 [_response appendContentString:@"</td>"];
710 [_response appendContentString:@"<td valign=\"top\""];
711 [self appendBgColor:_response inContext:_ctx day:4];
712 [_response appendContentCharacter:'>'];
714 [self appendContentToResponse:_response inContext:_ctx day:4];
715 [_response appendContentString:@"</td>"];
716 [_response appendContentString:@"</tr>"];
719 - (void)appendThirdRowToResponse:(WOResponse *)_response
720 inContext:(WOContext *)_ctx
722 /* third row (Mi, Sa, So ) */
725 showWeekend = (self->hideWeekend != nil)
726 ? [self->hideWeekend boolValueInComponent:[_ctx component]] ? NO : YES
729 [_response appendContentString:@"<tr>"];
730 [self appendDateTitleToResponse:_response inContext:_ctx day:2]; /* Wed */
732 [self appendDateTitleToResponse:_response inContext:_ctx day:5]; /* Sat */
733 [_response appendContentString:@"</tr>"];
735 [_response appendContentString:@"<tr>"];
737 [_response appendContentString:
739 ? @"<td rowspan=\"3\" valign=\"top\"" : @"<td valign=\"top\""];
740 [self appendBgColor:_response inContext:_ctx day:2]; /* Wed */
741 [_response appendContentCharacter:'>'];
743 [self appendContentToResponse:_response inContext:_ctx day:2]; /* Wed */
744 [_response appendContentString:@"</td>"];
747 [_response appendContentString:@"<td valign=\"top\""];
748 [self appendBgColor:_response inContext:_ctx day:5];
749 [_response appendContentCharacter:'>'];
751 [self appendContentToResponse:_response inContext:_ctx day:5];
752 [_response appendContentString:@"</td>"];
753 [_response appendContentString:@"</tr>"];
755 [_response appendContentString:@"<tr>"];
756 [self appendDateTitleToResponse:_response inContext:_ctx day:6];
757 [_response appendContentString:@"</tr>"];
759 [_response appendContentString:@"<tr>"];
761 [_response appendContentString:@"<td valign=\"top\""];
762 [self appendBgColor:_response inContext:_ctx day:6];
763 [_response appendContentCharacter:'>'];
765 [self appendContentToResponse:_response inContext:_ctx day:6];
766 [_response appendContentString:@"</td>"];
769 [_response appendContentString:@"</tr>"];
772 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
773 [self _calcMatrixInContext:_ctx];
775 [_response appendContentString:@"<table "];
776 [self appendExtraAttributesToResponse:_response inContext:_ctx];
777 [_response appendContentString:@">"];
779 /* first row (Mo,Do) */
780 [self appendFirstRowToResponse:_response inContext:_ctx];
782 /* second row (Di,Fr) */
783 [self appendSecondRowToResponse:_response inContext:_ctx];
785 /* third row (Mi, Sa, So ) */
786 [self appendThirdRowToResponse:_response inContext:_ctx];
788 [_response appendContentString:@"</table>"];
793 @end /* WeekOverview */
795 @interface WEWeekColumnViewTitleMode : WEContextConditional
798 @implementation WEWeekColumnViewTitleMode
799 - (NSString *)_contextKey {
800 return WEWeekColumnView_TitleMode;
802 - (NSString *)_didMatchKey {
803 return WEWeekColumnView_TitleModeDidMatch;
809 @interface WEWeekColumnViewInfoMode : WEContextConditional
812 @implementation WEWeekColumnViewInfoMode
813 - (NSString *)_contextKey {
814 return WEWeekColumnView_InfoMode;
820 @interface WEWeekColumnViewContentMode : WEContextConditional
823 @implementation WEWeekColumnViewContentMode
824 - (NSString *)_contextKey {
825 return WEWeekColumnView_ContentMode;