]> err.no Git - sope/blob - sope-appserver/WEExtensions/WEWeekColumnView.m
added strict OSX bundle dependencies
[sope] / sope-appserver / WEExtensions / WEWeekColumnView.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include "WEContextConditional.h"
23 #include <NGObjWeb/WODynamicElement.h>
24
25 /*
26     draws this:
27     
28       |---------------|---------------|
29       |Mo  <content>  | Do  <content> |             
30       |               |               |
31       |               |               |
32       |---------------|---------------|
33       |Di  <content>  | Fr  <content> |             
34       |               |               |
35       |               |               |
36       |---------------|---------------|
37       |Mi  <content>  | Sa  <content> |             
38       |               |---------------|
39       |               | So  <content> |
40       |---------------|---------------|
41 */
42
43 #define SecondsPerWeek (7 * 24 * 60 * 60)
44 #define SecondsPerDay      (24 * 60 * 60)
45 #define MatrixSections  7
46
47 @class NSMutableArray;
48
49
50 #define WEWeekColumnView_TitleMode         @"WEWeekColumnView_TitleMode"
51 #define WEWeekColumnView_TitleModeDidMatch @"WEWeekColumnView_TitleModeMatched"
52 #define WEWeekColumnView_InfoMode          @"WEWeekColumnView_InfoMode"
53 #define WEWeekColumnView_ContentMode       @"WEWeekColumnView_ContentMode"
54
55 @interface WEWeekColumnView : WODynamicElement
56 {
57 @protected
58   WOAssociation  *list;
59   WOAssociation  *item;
60   WOAssociation  *index;
61   WOAssociation  *identifier;
62   
63   WOAssociation  *dayIndex;
64   WOAssociation  *weekStart;
65   
66   WOAssociation  *startDateKey;
67   WOAssociation  *endDateKey;
68
69   WOAssociation  *titleColor;
70   WOAssociation  *contentColor;
71   
72   WOAssociation  *isInfoItem; // is current item info entry
73   WOAssociation  *infoItems;  // current info entries
74   
75   WOAssociation  *hideWeekend; /* should Sa/So be rendered? */
76   
77 @private
78   NSMutableArray *matrix[MatrixSections];
79   NSMutableArray *infos[MatrixSections];
80   BOOL           hasOwnTitle;
81   
82   WOElement      *template;
83 }
84 @end
85
86 #include <math.h> /* Needed for floor() */
87 #include "common.h"
88
89 @implementation WEWeekColumnView
90
91 static Class StrClass = Nil;
92
93 + (void)initialize {
94   StrClass = [NSString class];
95 }
96
97 static NSString *retStrForInt(int i) {
98   switch(i) {
99   case 0:  return @"0";
100   case 1:  return @"1";
101   case 2:  return @"2";
102   case 3:  return @"3";
103   case 4:  return @"4";
104   case 5:  return @"5";
105   case 6:  return @"6";
106   case 7:  return @"7";
107   case 8:  return @"8";
108   case 9:  return @"9";
109   case 10: return @"10";
110     // TODO: find useful count!
111   default:
112     return [[StrClass alloc] initWithFormat:@"%i", i];
113   }
114 }
115
116 - (id)initWithName:(NSString *)_name
117   associations:(NSDictionary *)_config
118   template:(WOElement *)_tmp
119 {
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");
129     
130     self->titleColor   = WOExtGetProperty(_config, @"titleColor");
131     self->contentColor = WOExtGetProperty(_config, @"contentColor");
132     
133     self->hideWeekend  = WOExtGetProperty(_config, @"hideWeekend");
134
135     if (self->startDateKey == nil) {
136       self->startDateKey =
137         [[WOAssociation associationWithValue:@"startDate"] retain];
138     }
139     if (self->endDateKey == nil) {
140       self->endDateKey = 
141         [[WOAssociation associationWithValue:@"endDate"] retain];
142     }
143
144     self->isInfoItem = WOExtGetProperty(_config, @"isInfoItem");
145     self->infoItems  = WOExtGetProperty(_config, @"infoItems");
146     
147     ASSIGN(self->template, _tmp);    
148   }
149   return self;
150 }
151
152 - (void)resetMatrix {
153   int i;
154   
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;
158   }
159 }
160
161 - (void)dealloc {
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];
175
176   [self resetMatrix];
177   [self->template release];
178   [super dealloc];
179 }
180
181 static inline void
182 _applyIdentifier(WEWeekColumnView *self, WOComponent *comp, NSString *_idx)
183 {
184   NSArray *array;
185   unsigned count, cnt;
186
187   array = [self->list valueInComponent:comp];
188   count = [array count];
189
190   if (count == 0)
191     return;
192     
193   /* find subelement for unique id */
194     
195   for (cnt = 0; cnt < count; cnt++) {
196       NSString *ident;
197       
198       if (self->index)
199         [self->index setUnsignedIntValue:cnt inComponent:comp];
200
201       if (self->item)
202         [self->item setValue:[array objectAtIndex:cnt] inComponent:comp];
203       
204       ident = [self->identifier stringValueInComponent:comp];
205
206       if ([ident isEqualToString:_idx]) {
207         /* found subelement with unique id */
208         return;
209       }
210     }
211     
212   [comp logWithFormat:
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];
217 }
218
219 static inline void
220 _applyIndex(WEWeekColumnView *self, WOComponent *comp, unsigned _idx)
221 {
222   NSArray *array;
223   unsigned count;
224   
225   array = [self->list valueInComponent:comp];
226   
227   if (self->index)
228     [self->index setUnsignedIntValue:_idx inComponent:comp];
229
230   if (self->item == nil)
231     return;
232
233   count = [array count];
234   if (_idx < count) {
235     [self->item setValue:[array objectAtIndex:_idx] inComponent:comp];
236     return;
237   }
238
239   [comp logWithFormat:
240             @"WEWeekColumnView: array did change, index is invalid."];
241   [self->item  setValue:nil          inComponent:comp];
242   [self->index setUnsignedIntValue:0 inComponent:comp];
243 }
244
245 - (void)_calcMatrixInContext:(WOContext *)_ctx {
246   WOComponent    *comp;
247   NSCalendarDate *startWeek;
248   NSArray        *array;
249   NSString       *startKey;
250   NSString       *endKey;
251   int            i, idx, idx2, cnt;
252   
253   [self resetMatrix];
254
255   [_ctx removeObjectForKey:WEWeekColumnView_TitleModeDidMatch];
256   [_ctx setObject:@"YES" forKey:WEWeekColumnView_TitleMode];
257   [self->template appendToResponse:nil inContext:_ctx];
258   [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
259   
260   if ([_ctx objectForKey:WEWeekColumnView_TitleModeDidMatch] != nil)
261     self->hasOwnTitle = YES;
262   else
263     self->hasOwnTitle = NO;
264   
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];
272   
273   for (i = 0, cnt = [array count]; i < cnt; i++) {
274     id             app;
275     NSCalendarDate *sd, *ed;
276     NSTimeInterval diff;
277     BOOL           isInfo;
278     
279     app = [array objectAtIndex:i];
280     sd  = [app valueForKey:startKey]; // startDate
281     ed  = [app valueForKey:endKey];   // endDate
282
283     if ((sd == nil) && (ed == nil)) continue;
284
285     if ((sd != nil) && (ed != nil) && [ed isEqual:[sd earlierDate:ed]]) {
286       NSCalendarDate *tmp;
287
288       tmp = sd;
289       sd  = ed;
290       ed  = tmp;
291     }
292     
293     diff  = [(sd ? sd : ed) timeIntervalSinceDate:startWeek];
294     
295     idx = floor((diff / SecondsPerWeek) * MatrixSections);
296
297     if ((self->item) && (self->isInfoItem)) {
298       [self->item setValue:app inComponent:comp];
299       isInfo = [[self->isInfoItem valueInComponent:comp] boolValue];
300     }
301     else isInfo = NO;
302
303     if ((0 <= idx) && (idx < MatrixSections)) {
304       if (isInfo) {
305         if (self->infos[idx] == nil)
306           self->infos[idx] = [[NSMutableArray alloc] initWithCapacity:2];      
307         [self->infos[idx] addObject:[NSNumber numberWithInt:i]];
308       }
309       else {
310         if (self->matrix[idx] == nil)
311           self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
312         [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
313       }
314     }
315     idx = (idx >= 0) ? idx+1 : idx;
316     diff = [ed timeIntervalSinceDate:startWeek];
317     
318     idx2 = floor((diff / SecondsPerWeek) * MatrixSections);
319     idx2 = (idx2 >= MatrixSections) ? (MatrixSections - 1) : idx2;
320
321     if (idx2 < 0) continue;
322     
323     while (idx <= idx2) {
324       idx = (idx < 0) ? 0 : idx;
325       if (isInfo) {
326         if (self->infos[idx] == nil)
327           self->infos[idx] = [[NSMutableArray alloc] initWithCapacity:2];      
328         [self->infos[idx] addObject:[NSNumber numberWithInt:i]];
329       }
330       else {
331         if (self->matrix[idx] == nil)
332           self->matrix[idx] = [[NSMutableArray alloc] initWithCapacity:4];
333         [self->matrix[idx] addObject:[NSNumber numberWithInt:i]];
334       }
335       idx++;
336     }
337   }
338 }
339
340 - (void)appendDateTitleToResponse:(WOResponse *)_response
341   inContext:(WOContext *)_ctx
342   day:(int)_day
343 {
344   WOComponent *comp;
345   NSString    *bgcolor;
346
347   comp = [_ctx component];
348   
349   bgcolor = [self->titleColor stringValueInComponent:comp];
350   
351   if ([self->dayIndex isValueSettable])
352     [self->dayIndex setIntValue:_day inComponent:comp];
353
354   [_response appendContentString:@"<td valign='top' align='left' width='50%'"];
355   if (bgcolor) {
356     [_response appendContentString:@" bgcolor=\""];
357     [_response appendContentString:bgcolor];
358     [_response appendContentCharacter:'"'];
359   }
360   [_response appendContentCharacter:'>'];
361
362   if (self->hasOwnTitle) {
363     NSString *s;
364     
365     [_ctx setObject:@"YES" forKey:WEWeekColumnView_TitleMode];
366     
367     [_ctx appendElementIDComponent:@"t"];
368     s = retStrForInt(_day);
369     [_ctx appendElementIDComponent:s];
370     [s release];
371     
372     [self->template appendToResponse:_response inContext:_ctx];
373
374     [_ctx deleteLastElementIDComponent]; // delete day index
375     [_ctx deleteLastElementIDComponent]; // delete "t"
376
377     [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
378   }
379   else {
380     NSCalendarDate *date;
381     
382     date = (self->weekStart)
383       ? [self->weekStart valueInComponent:comp]
384       : [NSCalendarDate calendarDate];
385     date = [date addTimeInterval:_day * SecondsPerDay];
386
387     [_response appendContentString:
388                @"<table cellpadding=0 width=100% border=0 cellspacing=0>"
389                @"<tr>"
390                @"<td align=left valign=top>"
391                @"<font color=\"black\" size=\"+2\"><b>"];
392  
393     [_response appendContentString:[date descriptionWithCalendarFormat:@"%d"]];
394
395     [_response appendContentString:
396                @"</b></font></td>"
397                @"<td align=\"center\" valign=\"top\">"
398                @"<font color=\"black\">"];
399
400     [_response appendContentString:[date descriptionWithCalendarFormat:@"%A"]];
401     [_response appendContentString:
402                @"</font>"
403                @"</td>"
404                @"</tr>"
405                @"</table>"];
406   }
407   [_response appendContentString:@"</td>"];
408 }
409
410 - (void)appendContentToResponse:(WOResponse *)_response
411   inContext:(WOContext *)_ctx
412   day:(int)_day
413 {
414   WOComponent *comp;
415   NSArray     *array;
416   id          app;
417   NSString    *s;
418   int         i, cnt, idx, count;
419
420   comp  = [_ctx component];
421   array = [self->list valueInComponent:comp];
422   count = [array count];
423
424   if ([self->infoItems isValueSettable]) {
425     if ((cnt = [self->infos[_day] count])) {
426       NSMutableArray *infoArr;
427       
428       infoArr = [NSMutableArray arrayWithCapacity:cnt];
429       for (i = 0; i < cnt; i++) {
430         idx = [[self->infos[_day] objectAtIndex:i] intValue];
431         
432         if (idx >= count) {
433           [self logWithFormat:
434                   @"WARNING: WEWeekOverview: info index out of range"];
435           continue;
436         }
437         [infoArr addObject:[array objectAtIndex:idx]];
438       }
439       [self->infoItems setValue:infoArr inComponent:comp];
440     }
441     else {
442       [self->infoItems setValue:[NSArray array] inComponent:comp];
443     }
444   }
445   
446   // *** append day info
447   [_ctx setObject:@"YES" forKey:WEWeekColumnView_InfoMode];
448   [_ctx appendElementIDComponent:@"i"];
449   s = retStrForInt(_day);
450   [_ctx appendElementIDComponent:s];
451   [s release];
452   [self->template appendToResponse:_response inContext:_ctx];
453   [_ctx deleteLastElementIDComponent]; // delete day
454   [_ctx deleteLastElementIDComponent]; // delete "i"
455   [_ctx removeObjectForKey:WEWeekColumnView_InfoMode];
456
457   // *** append day content
458   [_ctx appendElementIDComponent:@"c"];
459   s = retStrForInt(_day);
460   [_ctx appendElementIDComponent:s];
461   [s release];
462   
463   [_ctx setObject:@"YES" forKey:WEWeekColumnView_ContentMode];
464
465   for (i = 0, cnt = [self->matrix[_day] count]; i < cnt; i++) {
466     idx = [[self->matrix[_day] objectAtIndex:i] intValue];
467
468     if (idx >= count) {
469       NSLog(@"Warning! WEWeekColumnView: index out of range");
470       continue;
471     }
472     app = [array objectAtIndex:idx];
473
474     if ([self->item isValueSettable])
475       [self->item  setValue:app inComponent:comp];
476     if ([self->index isValueSettable])
477       [self->index setIntValue:idx inComponent:comp];
478
479     if (self->identifier == nil) {
480       s = retStrForInt(idx);
481       [_ctx appendElementIDComponent:s];
482       [s release];
483     }
484     else {
485       NSString *s;
486
487       s = [self->identifier stringValueInComponent:comp];
488       [_ctx appendElementIDComponent:s];
489     }
490     [self->template appendToResponse:_response inContext:_ctx];
491     [_ctx deleteLastElementIDComponent];
492   }
493   if (cnt == 0)
494     [_response appendContentString:@"&nbsp;"];
495   [_ctx removeObjectForKey:WEWeekColumnView_ContentMode];
496
497   [_ctx deleteLastElementIDComponent]; // delete day index
498   [_ctx deleteLastElementIDComponent]; // delete "c"
499 }
500
501 /* handling requests */
502
503 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
504   WOComponent *comp;
505   NSArray     *array;
506   int         i, count;
507   
508   comp  = [_ctx component];
509   array = [self->list valueInComponent:comp];
510   count = [array count];
511
512   /* titles */
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
521   }
522   [_ctx deleteLastElementIDComponent];  // delete day
523   [_ctx deleteLastElementIDComponent];  // delete title mode
524   [_ctx removeObjectForKey:WEWeekColumnView_TitleMode];
525   
526   /* infos */
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];
533     
534     [self->template takeValuesFromRequest:_req inContext:_ctx];
535     
536     [_ctx incrementLastElementIDComponent]; // increment day
537     [_ctx incrementLastElementIDComponent]; // in steps of 2
538   }
539   [_ctx deleteLastElementIDComponent];  // delete day
540   [_ctx deleteLastElementIDComponent];  // delete info mode
541   [_ctx removeObjectForKey:WEWeekColumnView_InfoMode];
542
543   // content
544   [self _calcMatrixInContext:_ctx];
545
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++) {
550     int     j, cnt, idx;
551     
552     cnt   = [self->matrix[i] count];
553     
554     if ([self->dayIndex isValueSettable])
555       [self->dayIndex setIntValue:i inComponent:comp];
556     
557     for (j = 0; j < cnt; j++) {
558       idx = [[self->matrix[i] objectAtIndex:j] intValue];
559       
560       if (idx >= count) {
561         NSLog(@"Warning! WEWeekColumnView: Index is out of range");
562         continue;
563       }
564       
565       _applyIndex(self, comp, idx);
566       
567       if (self->identifier) {
568         NSString *s;
569         
570         s = [self->identifier stringValueInComponent:comp];
571         [_ctx appendElementIDComponent:s];
572       }
573       else {
574         NSString *s;
575         
576         s = retStrForInt(idx);
577         [_ctx appendElementIDComponent:s];
578         [s release];
579       }
580
581       [self->template takeValuesFromRequest:_req inContext:_ctx];
582       
583       [_ctx deleteLastElementIDComponent];   // delete index-id
584     }
585     [_ctx incrementLastElementIDComponent]; // increase day-id
586   }
587   [_ctx deleteLastElementIDComponent];  // delete day-id
588   [_ctx deleteLastElementIDComponent];  // delete content mode
589   [_ctx removeObjectForKey:WEWeekColumnView_ContentMode];
590   
591   [self resetMatrix];  
592 }
593
594 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
595   WOComponent *comp;
596   id          result = nil;
597   NSString    *cid;
598   NSString    *dayId;
599
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];
606
607   comp = [_ctx component];
608   
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];
613   }
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];
618   }
619   else if ([cid isEqualToString:@"c"]) {
620     NSString *idxId;
621
622     if ([self->dayIndex isValueSettable])
623       [self->dayIndex setIntValue:[dayId intValue] inComponent:comp];
624
625     if ((idxId = [_ctx currentElementID])) {
626       [_ctx consumeElementID];               // consume index-id
627       [_ctx appendElementIDComponent:idxId];
628
629       if (self->identifier)
630         _applyIdentifier(self, comp, idxId);
631       else
632         _applyIndex(self, comp, [idxId intValue]);
633
634       result = [self->template invokeActionForRequest:_req inContext:_ctx];
635
636       [_ctx deleteLastElementIDComponent]; // delete index-id
637     }
638   }
639   else
640     [self logWithFormat:@"WARNING! WEWeekColumnView: wrong section"];
641   
642   [_ctx deleteLastElementIDComponent]; // delete section id
643   [_ctx deleteLastElementIDComponent]; // delete mode
644   
645   return result;
646 }
647
648 /* generating response */
649
650 - (void)appendBgColor:(WOResponse *)_response
651   inContext:(WOContext *)_ctx
652   day:(unsigned)_day 
653 {
654   NSString *bg;
655   
656   if ([self->dayIndex isValueSettable])
657     [self->dayIndex setIntValue:_day inComponent:[_ctx component]];
658   
659   if ((bg = [self->contentColor stringValueInComponent:[_ctx component]])) {
660     [_response appendContentString:@" bgcolor=\""];
661     [_response appendContentString:bg];
662     [_response appendContentCharacter:'"'];
663   }
664 }
665
666 - (void)appendFirstRowToResponse:(WOResponse *)_response
667   inContext:(WOContext *)_ctx 
668 {
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>"];
674
675     [_response appendContentString:@"<tr>"];
676     
677     [_response appendContentString:@"<td valign=\"top\""];
678     [self appendBgColor:_response inContext:_ctx day:0];
679     [_response appendContentCharacter:'>'];
680     
681     [self appendContentToResponse:_response inContext:_ctx day:0];
682     [_response appendContentString:@"</td>"];
683     
684     [_response appendContentString:@"<td valign=\"top\""];
685     [self appendBgColor:_response inContext:_ctx day:3];
686     [_response appendContentCharacter:'>'];
687     
688     [self appendContentToResponse:_response inContext:_ctx day:3];
689     [_response appendContentString:@"</td>"];
690     [_response appendContentString:@"</tr>"];
691 }
692
693 - (void)appendSecondRowToResponse:(WOResponse *)_response
694   inContext:(WOContext *)_ctx 
695 {
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>"];
701
702     [_response appendContentString:@"<tr>"];
703
704     [_response appendContentString:@"<td valign=\"top\""];
705     [self appendBgColor:_response inContext:_ctx day:1];
706     [_response appendContentCharacter:'>'];
707
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:'>'];
713     
714     [self appendContentToResponse:_response inContext:_ctx day:4];
715     [_response appendContentString:@"</td>"];
716     [_response appendContentString:@"</tr>"];
717 }
718
719 - (void)appendThirdRowToResponse:(WOResponse *)_response
720   inContext:(WOContext *)_ctx 
721 {
722   /* third row (Mi, Sa, So ) */
723   BOOL showWeekend;
724
725   showWeekend = (self->hideWeekend != nil)
726     ? [self->hideWeekend boolValueInComponent:[_ctx component]] ? NO : YES
727     : YES;
728   
729   [_response appendContentString:@"<tr>"];
730   [self appendDateTitleToResponse:_response inContext:_ctx day:2]; /* Wed */
731   if (showWeekend)
732     [self appendDateTitleToResponse:_response inContext:_ctx day:5]; /* Sat */
733   [_response appendContentString:@"</tr>"];
734
735   [_response appendContentString:@"<tr>"];
736     
737   [_response appendContentString:
738                showWeekend 
739              ? @"<td rowspan=\"3\" valign=\"top\"" : @"<td valign=\"top\""];
740   [self appendBgColor:_response inContext:_ctx day:2]; /* Wed */
741   [_response appendContentCharacter:'>'];
742   
743   [self appendContentToResponse:_response inContext:_ctx day:2]; /* Wed */
744   [_response appendContentString:@"</td>"];
745   
746   if (showWeekend) {
747     [_response appendContentString:@"<td valign=\"top\""];
748     [self appendBgColor:_response inContext:_ctx day:5];
749     [_response appendContentCharacter:'>'];
750     
751     [self appendContentToResponse:_response inContext:_ctx day:5];
752     [_response appendContentString:@"</td>"];
753     [_response appendContentString:@"</tr>"];
754
755     [_response appendContentString:@"<tr>"];
756     [self appendDateTitleToResponse:_response inContext:_ctx day:6];
757     [_response appendContentString:@"</tr>"];
758
759     [_response appendContentString:@"<tr>"];
760     
761     [_response appendContentString:@"<td valign=\"top\""];
762     [self appendBgColor:_response inContext:_ctx day:6];
763     [_response appendContentCharacter:'>'];
764   
765     [self appendContentToResponse:_response inContext:_ctx day:6];
766     [_response appendContentString:@"</td>"];
767   }
768   
769   [_response appendContentString:@"</tr>"];
770 }
771
772 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
773   [self _calcMatrixInContext:_ctx];
774   
775   [_response appendContentString:@"<table "];
776   [self appendExtraAttributesToResponse:_response inContext:_ctx];
777   [_response appendContentString:@">"];  
778   
779   /* first row (Mo,Do) */
780   [self appendFirstRowToResponse:_response inContext:_ctx];
781   
782   /* second row (Di,Fr) */
783   [self appendSecondRowToResponse:_response inContext:_ctx];
784   
785   /* third row (Mi, Sa, So ) */
786   [self appendThirdRowToResponse:_response inContext:_ctx];
787   
788   [_response appendContentString:@"</table>"];
789
790   [self resetMatrix];
791 }
792
793 @end /* WeekOverview */
794
795 @interface WEWeekColumnViewTitleMode : WEContextConditional
796 @end
797
798 @implementation WEWeekColumnViewTitleMode
799 - (NSString *)_contextKey {
800   return WEWeekColumnView_TitleMode;
801 }
802 - (NSString *)_didMatchKey {
803   return WEWeekColumnView_TitleModeDidMatch;
804 }
805 @end
806
807 // --
808
809 @interface WEWeekColumnViewInfoMode : WEContextConditional
810 @end
811
812 @implementation WEWeekColumnViewInfoMode
813 - (NSString *)_contextKey {
814   return WEWeekColumnView_InfoMode;
815 }
816 @end
817
818 // --
819
820 @interface WEWeekColumnViewContentMode : WEContextConditional
821 @end
822
823 @implementation WEWeekColumnViewContentMode
824 - (NSString *)_contextKey {
825   return WEWeekColumnView_ContentMode;
826 }
827 @end