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 <NGObjWeb/WODynamicElement.h> 23#include <NGObjWeb/WOAssociation.h> 24#include <NGObjWeb/WOContext.h> 25#include <NGObjWeb/WOResponse.h> 26#include "WETableCalcMatrix.h" 27#include "common.h" 28 29/* 30 for examples of this element, look at SkySchedulerViews chart-views. 31*/ 32 33/* context keys */ 34static NSString *WETableMatrix_Query = @"WETableMatrix_Query"; 35static NSString *WETableMatrix_Mode = @"WETableMatrix_Mode"; 36static NSString *WETableMatrix_Index = @"WETableMatrix_Index"; 37static NSString *WETableMatrix_Count = @"WETableMatrix_Count"; 38static NSString *WETableMatrix_ColSpan = @"WETableMatrix_ColSpan"; 39static NSString *WETableMatrix_RowSpan = @"WETableMatrix_RowSpan"; 40 41@interface WETableMatrix : WODynamicElement 42{ 43 WOAssociation *list; /* array of objects */ 44 WOAssociation *item; /* current object */ 45 46 WOAssociation *rows; /* array of row objects (eg days) */ 47 WOAssociation *columns; /* array of column objects (eg times of day) */ 48 WOAssociation *row; /* current row object */ 49 WOAssociation *column; /* current column object */ 50 51 WOAssociation *itemActive; /* query whether item is active in row/column */ 52 WOAssociation *isRowActive; 53 WOAssociation *isColumnActive; 54 55 WOElement *template; 56 57 /* transient, not reentrant (need to lock) */ 58 WOComponent *component; 59 NSArray *_rows; 60 NSArray *_cols; 61 NSArray *objs; 62 NSSet *subElems; 63} 64 65@end 66 67@interface WEHSpanTableMatrix : WETableMatrix 68@end 69 70@interface WEVSpanTableMatrix : WETableMatrix 71{ 72 WOAssociation *rowHeight; /* height of TR tag */ 73 WOAssociation *noSpanInEmptyCells; /* do empty cells span rows ? */ 74} 75@end 76 77static BOOL genComments = NO; 78 79@implementation WETableMatrix 80 81// premature: don't know a "good" count 82static NSNumber *smap[10] = { nil,nil,nil,nil,nil,nil,nil,nil,nil,nil }; 83static Class StrClass = Nil; 84static Class NumClass = Nil; 85 86+ (void)initialize { 87 static BOOL didInit = NO; 88 int i; 89 if (didInit) return; 90 didInit = YES; 91 92 StrClass = [NSString class]; 93 NumClass = [NSNumber class]; 94 for (i = 0; i < 10; i++) 95 smap[i] = [[NumClass numberWithUnsignedInt:i] retain]; 96} 97 98static NSNumber *numForUInt(unsigned int i) { 99 // TODO: prof 100 if (i < 10) return smap[i]; 101 return [NumClass numberWithUnsignedInt:i]; 102} 103 104- (id)initWithName:(NSString *)_name 105 associations:(NSDictionary *)_config 106 template:(WOElement *)_subs 107{ 108 if ((self = [super initWithName:_name associations:_config template:_subs])) { 109 self->list = WOExtGetProperty(_config, @"list"); 110 self->item = WOExtGetProperty(_config, @"item"); 111 self->rows = WOExtGetProperty(_config, @"rows"); 112 self->columns = WOExtGetProperty(_config, @"columns"); 113 self->row = WOExtGetProperty(_config, @"row"); 114 self->column = WOExtGetProperty(_config, @"column"); 115 self->itemActive = WOExtGetProperty(_config, @"itemActive"); 116 self->isRowActive = WOExtGetProperty(_config, @"isRowActive"); 117 self->isColumnActive = WOExtGetProperty(_config, @"isColumnActive"); 118 119 self->template = [_subs retain]; 120 } 121 return self; 122} 123 124- (void)dealloc { 125 [self->isRowActive release]; 126 [self->isColumnActive release]; 127 [self->itemActive release]; 128 [self->row release]; 129 [self->column release]; 130 [self->rows release]; 131 [self->columns release]; 132 [self->list release]; 133 [self->item release]; 134 [self->template release]; 135 [super dealloc]; 136} 137 138/* matrix delegate */ 139 140- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix 141 shouldPlaceObject:(id)_object 142 atPosition:(unsigned)_x :(unsigned)_y 143{ 144 id _row, _col; 145 BOOL doPlace; 146 147 _col = [self->_cols objectAtIndex:_x]; 148 _row = [self->_rows objectAtIndex:_y]; 149 150 /* setup context in component */ 151 [self->row setValue:_row inComponent:self->component]; 152 [self->column setValue:_col inComponent:self->component]; 153 [self->item setValue:_object inComponent:self->component]; 154 155#if 0 156 NSLog(@"%i/%i: col %@ row %@", _x,_y, _col, _row); 157#endif 158 159 /* check */ 160 doPlace = [self->itemActive boolValueInComponent:self->component]; 161#if 0 162 NSLog(@" %@ placed: %s", self->itemActive, doPlace ? "yes" : "no"); 163#endif 164 165 return doPlace; 166} 167 168- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix 169 shouldProcessColumn:(unsigned)_x 170 forObject:(id)_object 171{ 172 if (!self->isColumnActive) 173 return YES; 174 175 [self->column setValue:[self->_cols objectAtIndex:_x] 176 inComponent:self->component]; 177 [self->item setValue:_object inComponent:self->component]; 178 179 return [self->isColumnActive boolValueInComponent:self->component]; 180} 181- (BOOL)tableCalcMatrix:(WETableCalcMatrix *)_matrix 182 shouldProcessRow:(unsigned)_y 183 forObject:(id)_object 184{ 185 if (!self->isRowActive) 186 return YES; 187 188 [self->row setValue:[self->_rows objectAtIndex:_y] 189 inComponent:self->component]; 190 [self->item setValue:_object inComponent:self->component]; 191 192 return [self->isRowActive boolValueInComponent:self->component]; 193} 194 195/* HTML generation */ 196 197- (NSArray *)spansFromMatrix:(WETableCalcMatrix *)_matrix { 198 [self logWithFormat:@"ERROR: subclasses should override %@!", 199 NSStringFromSelector(_cmd)]; 200 return nil; 201} 202- (void)appendSpans:(NSArray *)_spans 203 toResponse:(WOResponse *)_response 204 inContext:(WOContext *)_ctx 205{ 206 [self logWithFormat:@"ERROR: subclasses should override %@!", 207 NSStringFromSelector(_cmd)]; 208} 209 210- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx { 211 NSLog(@"WARNING(WETableMatrix): unsupported invokeActionForRequest called!"); 212 return [super invokeActionForRequest:_req inContext:_ctx]; 213} 214 215 216- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { 217 NSAutoreleasePool *pool; 218 WETableCalcMatrix *matrix; 219 NSArray *allSpans; 220 unsigned rowCount, colCount; 221 222 if ([_ctx isRenderingDisabled]) { 223 [self->template appendToResponse:_response inContext:_ctx]; 224 return; 225 } 226 227 self->component = [_ctx component]; 228 self->objs = 229 [[[self->list valueInComponent:self->component] copy] autorelease]; 230 self->_rows = 231 [[[self->rows valueInComponent:self->component] copy] autorelease]; 232 self->_cols = 233 [[[self->columns valueInComponent:self->component] copy] autorelease]; 234 235 rowCount = [self->_rows count]; 236 colCount = [self->_cols count]; 237 238 /* query subelements */ 239 { 240 NSMutableSet *qs; 241 242 qs = [[NSMutableSet alloc] init]; 243 [_ctx setObject:qs forKey:WETableMatrix_Query]; 244 [self->template appendToResponse:_response inContext:_ctx]; 245 [_ctx removeObjectForKey:WETableMatrix_Query]; 246 self->subElems = [[qs copy] autorelease]; 247 [qs release]; 248 } 249 250 if ([self->subElems count] == 0) { 251 /* no content */ 252 [self warnWithFormat:@"no sub-elements !"]; 253 return; 254 } 255 256#if 0 257 NSLog(@"subelems: %@", [self->subElems allObjects]); 258#endif 259 260 /* fill matrix and calculate spans */ 261 262 pool = [[NSAutoreleasePool alloc] init]; 263 { 264 matrix = [[WETableCalcMatrix alloc] initWithSize:colCount:rowCount]; 265 [matrix setDelegate:self]; 266 [matrix placeObjects:objs]; 267 allSpans = [[self spansFromMatrix:matrix] copy]; 268 [matrix release]; matrix = nil; 269 } 270 [pool release]; pool = nil; 271 [allSpans autorelease]; 272 273 /* generate vertical table */ 274 275 pool = [[NSAutoreleasePool alloc] init]; 276 277 [_response appendContentString:@"<table"]; 278 [self appendExtraAttributesToResponse:_response inContext:_ctx]; 279 [_response appendContentString:@">"]; 280 281 [self appendSpans:allSpans 282 toResponse:_response 283 inContext:_ctx]; 284 285 [_response appendContentString:@"</table>"]; 286 287 /* remove context keys */ 288 [_ctx removeObjectForKey:WETableMatrix_Mode]; 289 [_ctx removeObjectForKey:WETableMatrix_Index]; 290 [_ctx removeObjectForKey:WETableMatrix_Count]; 291 [_ctx removeObjectForKey:WETableMatrix_ColSpan]; 292 [_ctx removeObjectForKey:WETableMatrix_RowSpan]; 293 294 /* reset transients */ 295 self->subElems = nil; 296 self->_rows = nil; 297 self->_cols = nil; 298 self->objs = nil; 299 self->component = nil; 300 [pool release]; 301} 302 303@end /* WETableMatrix */ 304 305@implementation WEVSpanTableMatrix 306 307- (id)initWithName:(NSString *)_name 308 associations:(NSDictionary *)_config 309 template:(WOElement *)_subs 310{ 311 if ((self = [super initWithName:_name associations:_config template:_subs])) { 312 self->rowHeight = WOExtGetProperty(_config, @"rowHeight"); 313 self->noSpanInEmptyCells = WOExtGetProperty(_config, @"noSpanInEmptyCells"); 314 } 315 return self; 316} 317 318- (void)dealloc { 319 [self->noSpanInEmptyCells release]; 320 [self->rowHeight release]; 321 [super dealloc]; 322} 323 324- (NSArray *)spansFromMatrix:(WETableCalcMatrix *)_matrix { 325 return [_matrix columnSpans]; 326} 327 328- (void)_genEmptyCellWithRowSpan:(int)_span 329 toResponse:(WOResponse *)_response 330 inContext:(WOContext *)_ctx 331{ 332 NSString *s; 333 334 if (_span > 1) { 335 char buf[16]; 336 sprintf(buf, "%i", _span); 337 s = [[StrClass alloc] initWithCString:buf]; 338 } 339 else 340 s = @"1"; 341 342 if ([self->subElems containsObject:@"empty"]) { 343 if (_span > 0) 344 [_ctx setObject:s forKey:WETableMatrix_RowSpan]; 345 346 [_ctx setObject:@"empty" forKey:WETableMatrix_Mode]; 347 348 [self->template appendToResponse:_response inContext:_ctx]; 349 350 if (_span > 0) 351 [_ctx removeObjectForKey:WETableMatrix_RowSpan]; 352 } 353 else { 354 [_response appendContentString:@"<td"]; 355 if (_span > 1) { 356 [_response appendContentString:@" rowspan=\""]; 357 [_response appendContentString:s]; 358 [_response appendContentString:@"\""]; 359 } 360 [_response appendContentString:@">"]; 361 362 [_response appendContentString:@" "]; 363 [_response appendContentString:@"</td>\n"]; 364 } 365 366 [s release]; 367} 368 369- (void)appendSpans:(NSArray *)_spans 370 toResponse:(WOResponse *)_response 371 inContext:(WOContext *)_ctx 372{ 373 WOComponent *sComponent; 374#if 0 // hh: unused 375 NSString *horizWidth; 376#endif 377 unsigned columnCount, rowCount; 378 BOOL noEmptySpan; // empty cells do not have ROWSPAN (more cells are written) 379 380 sComponent = [_ctx component]; 381 columnCount = [self->_cols count]; 382 rowCount = [self->_rows count]; 383#if 0 // hh: unused 384 horizWidth = 385 [StrClass stringWithFormat:@"%d%%", (unsigned)(100.0/columnCount)]; 386#endif 387 388 noEmptySpan = [self->noSpanInEmptyCells boolValueInComponent:sComponent]; 389 390 [_ctx setObject:numForUInt(columnCount) forKey:WETableMatrix_Count]; 391 392 /* head row */ 393 if ([self->subElems containsObject:@"top"]) { 394 unsigned x; 395 int numOfLeftLabels; 396 397 numOfLeftLabels = 0; 398 if ([self->subElems containsObject:@"left"]) 399 numOfLeftLabels++; 400 401 [_response appendContentString:@"<tr>\n"]; 402 403 /* left/top edge */ 404 if (numOfLeftLabels > 0) { 405 char buf[8]; 406 NSString *s; 407 408 sprintf(buf, "%i", numOfLeftLabels); 409 s = [[StrClass alloc] initWithCString:buf]; 410 411 if ([self->subElems containsObject:@"topleft"]) { 412 [_ctx setObject:s forKey:WETableMatrix_ColSpan]; 413 [_ctx setObject:@"topleft" forKey:WETableMatrix_Mode]; 414 415 [self->template appendToResponse:_response inContext:_ctx]; 416 417 [_ctx removeObjectForKey:WETableMatrix_ColSpan]; 418 } 419 else { 420 [_response appendContentString:@" <td"]; 421 if (numOfLeftLabels > 1) { 422 [_response appendContentString:@" colspan=\""]; 423 [_response appendContentString:s]; 424 [_response appendContentString:@"\""]; 425 } 426 [_response appendContentString:@"> </td>\n"]; 427 } 428 [s release]; 429 } 430 431 /* header */ 432 [_ctx setObject:@"top" forKey:WETableMatrix_Mode]; 433 434 for (x = 0; x < columnCount; x++) { 435 NSArray *spans; 436 char buf[64]; 437 NSString *s; 438 439 spans = [_spans objectAtIndex:x]; 440 441#if GS_64BIT_OLD 442 sprintf(buf, "%ld", [spans count]); 443#else 444 sprintf(buf, "%ld", [spans count]); 445#endif 446 s = [[StrClass alloc] initWithCString:buf]; 447 [_ctx setObject:s forKey:WETableMatrix_ColSpan]; 448 449 [self->column setValue:[self->_cols objectAtIndex:x] 450 inComponent:sComponent]; 451 [_ctx setObject:numForUInt(x) forKey:WETableMatrix_Index]; 452 453 [self->template appendToResponse:_response inContext:_ctx]; 454 455 [s release]; s = nil; 456 } 457 458 [_response appendContentString:@"</tr>"]; 459 } 460 461 [_ctx removeObjectForKey:WETableMatrix_ColSpan]; 462 [_ctx removeObjectForKey:WETableMatrix_RowSpan]; 463 [_ctx removeObjectForKey:WETableMatrix_Index]; 464 465 /* body rows */ 466 { 467 unsigned y; 468 469 /* foreach row */ 470 for (y = 0; y < rowCount; y++) { 471 unsigned x; 472 473 [self->row setValue:[self->_rows objectAtIndex:y] 474 inComponent:[_ctx component]]; 475 476 if (self->rowHeight) { 477 [_response appendContentString:@"<tr height=\""]; 478 [_response appendContentString: 479 [self->rowHeight stringValueInComponent:sComponent]]; 480 [_response appendContentString:@"\">"]; 481 } 482 else { 483 [_response appendContentString:@"<tr>"]; 484 } 485 if (genComments) { 486 NSString *s; 487 s = [[StrClass alloc] initWithFormat:@"<!-- row %i -->\n", y]; 488 [_response appendContentString:s]; 489 [s release]; 490 } 491 492 /* left edge */ 493 { 494 char buf[64]; 495 NSString *s; 496 497 [_ctx setObject:@"left" forKey:WETableMatrix_Mode]; 498 499 sprintf(buf, "%i", y); 500 s = [[StrClass alloc] initWithCString:buf]; 501 502 [_ctx setObject:numForUInt(y) forKey:WETableMatrix_Index]; 503 504 [self->template appendToResponse:_response inContext:_ctx]; 505 [s release]; 506 } 507 508 /* foreach column */ 509 for (x = 0; x < columnCount; x++) { 510 NSArray *spans; 511 unsigned i; 512 513 spans = [_spans objectAtIndex:x]; 514 515 if ([spans count] == 0) { /* no content cells */ 516 if ((y == 0) || noEmptySpan) { 517 /* max rowspan, only encode in first row */ 518 519 [self _genEmptyCellWithRowSpan:(noEmptySpan ? 1 : rowCount) 520 toResponse:_response 521 inContext:_ctx]; 522 } 523 continue; 524 } 525 526 /* foreach sub-columns (title-COLSPAN=subcell-count) */ 527 528 for (i = 0; i < [spans count]; i++) { 529 NSArray *thread; /* sub-column top-down */ 530 unsigned j; 531 532 thread = [spans objectAtIndex:i]; 533 NSCAssert([thread count] > 0, @"no contents in thread"); 534 535 for (j = 0; j < [thread count]; j++) { 536 id span; 537 538 span = [thread objectAtIndex:j]; 539 if (![span occupiesIndex:y]) 540 continue; 541 542 if ([span startsAtIndex:y]) { 543 char buf[64]; 544 NSString *s; 545 546 sprintf(buf, "%i", [span size]); 547 s = [[StrClass alloc] initWithCString:buf]; 548 [_ctx setObject:s forKey:WETableMatrix_RowSpan]; 549 550 [self->column setValue:[self->_cols objectAtIndex:x] 551 inComponent:self->component]; 552 553 if ([span object]) { 554 /* setup context */ 555 [self->item setValue:[span object] inComponent:self->component]; 556 557 /* generate body */ 558 [_ctx setObject:@"content" forKey:WETableMatrix_Mode]; 559 560 [self->template appendToResponse:_response inContext:_ctx]; 561 } 562 else { 563 [self _genEmptyCellWithRowSpan:(noEmptySpan ? 1 : [span size]) 564 toResponse:_response 565 inContext:_ctx]; 566 } 567 568 [_ctx removeObjectForKey:WETableMatrix_RowSpan]; 569 [s release]; s = nil; 570 } 571 else if (noEmptySpan) { 572 if ([span object] == nil) { 573 [self _genEmptyCellWithRowSpan:1 574 toResponse:_response 575 inContext:_ctx]; 576 } 577 } 578 } 579 } /* end of 'foreach sub-columns (title-COLSPAN=subcell-count)' */ 580 } /* end of 'foreach column' */ 581 [_response appendContentString:@"</tr>"]; 582 } 583 } 584 585 /* footer row */ 586 587 if ([self->subElems containsObject:@"bottom"]) { 588 } 589} 590 591@end /* WEVSpanTableMatrix */ 592 593@implementation WEHSpanTableMatrix 594 595- (NSArray *)spansFromMatrix:(WETableCalcMatrix *)_matrix { 596 return [_matrix rowSpans]; 597} 598 599- (void)appendVerticalSpan:(NSArray *)_threads 600 toResponse:(WOResponse *)_response 601 inContext:(WOContext *)_ctx 602{ 603 unsigned x, width; 604 605 width = [self->_cols count]; 606 607 for (x = 0; x < width; x++) { /* foreach table column */ 608 unsigned j, tc; 609 610 for (j = 0, tc = [_threads count]; j < tc; j++) { 611 id span; 612 613 span = [_threads objectAtIndex:j]; 614 if (![span occupiesIndex:x]) 615 continue; 616 617 if ([span startsAtIndex:x]) { 618 NSString *s; 619 char buf[64]; 620 621 sprintf(buf, "%d", [span size]); 622 s = [[StrClass alloc] initWithCString:buf]; 623 [_ctx setObject:s forKey:WETableMatrix_ColSpan]; 624 625 if ([span object]) { 626 /* setup context */ 627 [self->column setValue:[self->_cols objectAtIndex:x] 628 inComponent:self->component]; 629 [self->item setValue:[span object] inComponent:self->component]; 630 631 /* generate body */ 632 [_ctx setObject:@"content" forKey:WETableMatrix_Mode]; 633 [self->template appendToResponse:_response inContext:_ctx]; 634 } 635 else { 636 /* generate empty body */ 637 if ([self->subElems containsObject:@"empty"]) { 638 [_ctx setObject:@"empty" forKey:WETableMatrix_Mode]; 639 [self->template appendToResponse:_response inContext:_ctx]; 640 } 641 else { 642 [_response appendContentString:@"<td colspan=\""]; 643 [_response appendContentString:s]; 644 [_response appendContentString:@"\">"]; 645 [_response appendContentString:@" "]; 646 [_response appendContentString:@"</td>\n"]; 647 } 648 } 649 [s release]; s = nil; 650 } 651 } 652 } 653} 654 655- (void)appendSpans:(NSArray *)_spans 656 toResponse:(WOResponse *)_response 657 inContext:(WOContext *)_ctx 658{ 659 WOComponent *sComponent; 660#if 0 // hh: unused 661 NSString *horizWidth; 662#endif 663 unsigned columnCount; 664 665 sComponent = [_ctx component]; 666 columnCount = [self->_cols count]; 667#if 0 // hh: unused 668 horizWidth = 669 [StrClass stringWithFormat:@"%d%%", (unsigned)(100.0/columnCount)]; 670#endif 671 672 [_ctx setObject:numForUInt(columnCount) forKey:WETableMatrix_Count]; 673 674 /* head row */ 675 676 if ([self->subElems containsObject:@"top"]) { 677 unsigned i, count; 678 679 [_response appendContentString:@"<tr>"]; 680 681 /* edge */ 682 if ([self->subElems containsObject:@"left"]) 683 [_response appendContentString:@"<td> </td>"]; 684 685 /* header */ 686 [_ctx setObject:@"top" forKey:WETableMatrix_Mode]; 687 count = [self->_cols count]; 688 689 for (i = 0; i < count; i++) { 690 [_ctx setObject:numForUInt(i) forKey:WETableMatrix_Index]; 691 692 [self->column setValue:[self->_cols objectAtIndex:i] 693 inComponent:sComponent]; 694 695 [self->template appendToResponse:_response inContext:_ctx]; 696 } 697 [_response appendContentString:@"</tr>"]; 698 } 699 700 /* body rows */ 701 { 702 unsigned y, width, height; 703 704 width = [self->_cols count]; 705 height = [self->_rows count]; 706 707 for (y = 0; y < height; y++) { /* foreach row */ 708 NSArray *rowSpans; 709 unsigned i, count; 710 711 /* apply context */ 712 [self->row setValue:[self->_rows objectAtIndex:y] 713 inComponent:self->component]; 714 715 /* get span */ 716 rowSpans = [_spans objectAtIndex:y]; 717 count = [rowSpans count]; 718 719 /* begin first row */ 720 [_response appendContentString:@"<tr>"]; 721 722 /* left edge */ 723 { 724 char buf[64]; 725 NSString *s; 726 727 sprintf(buf, "%d", count); 728 s = [[StrClass alloc] initWithCString:buf]; 729 [_ctx setObject:s forKey:WETableMatrix_RowSpan]; 730 731 [_ctx setObject:@"left" forKey:WETableMatrix_Mode]; 732 733 [_ctx setObject:numForUInt(y) forKey:WETableMatrix_Index]; 734 [self->template appendToResponse:_response inContext:_ctx]; 735 [s release]; s = nil; 736 [_ctx removeObjectForKey:WETableMatrix_RowSpan]; 737 } 738#if 0 /* hh: why is this commented out ? */ 739 /* left label ? */ 740 [_response appendContentString:@"<td"]; 741 if (count > 1) { 742 NSString *s; 743 744 [_response appendContentString:@" rowspan=\""]; 745 s = [[StrClass alloc] initWithFormat:@"%d", count]; 746 [_response appendContentString:s]; 747 [s release]; 748 [_response appendContentString:@"\""]; 749 } 750 [_response appendContentString:@">"]; 751 [genLabel]; 752 [_response appendContentString:@"</td>"]; 753#endif 754 755 /* check for empty span */ 756 if (count == 0) { 757 NSString *s; 758 759 s = [[StrClass alloc] initWithFormat:@"%d", width]; 760 761 /* max rowspan, only encode in first row */ 762 [_ctx setObject:@"empty" forKey:WETableMatrix_Mode]; 763 [_ctx setObject:s forKey:WETableMatrix_ColSpan]; 764 [self->template appendToResponse:_response inContext:_ctx]; 765 [_ctx removeObjectForKey:WETableMatrix_ColSpan]; 766#if 0 /* hh: why is this commented out ? */ 767 768 [_response appendContentString:@"<td colspan=\""]; 769 [_response appendContentString:s]; 770 [_response appendContentString:@"\"> </td>"]; 771 772 /* close completly filled row */ 773 [_response appendContentString:@"</tr>"]; 774#endif 775 [s release]; 776 continue; 777 } 778 779 /* first span (same row like vertical label) */ 780 if (count > 0) { 781 NSArray *thread; 782 783 thread = [rowSpans objectAtIndex:0]; 784 785 [self appendVerticalSpan:thread 786 toResponse:_response 787 inContext:_ctx]; 788 } 789 /* close first row */ 790 [_response appendContentString:@"</tr>"]; 791 792 for (i = 1; i < count; i++) { /* foreach additional span */ 793 NSArray *thread; 794 795 thread = [rowSpans objectAtIndex:i]; 796 797 [_response appendContentString:@"<tr>"]; 798 799 [self appendVerticalSpan:thread 800 toResponse:_response 801 inContext:_ctx]; 802 803 [_response appendContentString:@"</tr>"]; 804 } 805 [_ctx removeObjectForKey:WETableMatrix_ColSpan]; 806 } 807 } 808 809 /* footer row */ 810 811 if ([self->subElems containsObject:@"bottom"]) { 812 unsigned i, count; 813 814 [_response appendContentString:@"<tr>"]; 815 816 /* edge */ 817 if ([self->subElems containsObject:@"left"]) 818 [_response appendContentString:@"<td> </td>"]; 819 820 /* footer */ 821 822 [_ctx setObject:@"bottom" forKey:WETableMatrix_Mode]; 823 824 count = [self->_cols count]; 825 826 for (i = 0; i < count; i++) { 827 [_ctx setObject:numForUInt(i) forKey:WETableMatrix_Index]; 828 829 [self->column setValue:[self->_cols objectAtIndex:i] 830 inComponent:sComponent]; 831 832 [self->template appendToResponse:_response inContext:_ctx]; 833 } 834 [_response appendContentString:@"</tr>"]; 835 } 836} 837 838@end /* WEVSpanTableMatrix */ 839