home *** CD-ROM | disk | FTP | other *** search
- //=============================================================================
- //
- // Copyright (C) 1995 by Paul S. McCarthy and Eric Sunshine.
- // Written by Paul S. McCarthy and Eric Sunshine.
- // All Rights Reserved.
- //
- // This notice may not be removed from this source code.
- //
- // This object is included in the MiscKit by permission from the authors
- // and its use is governed by the MiscKit license, found in the file
- // "License.rtf" in the MiscKit distribution. Please refer to that file
- // for a list of all applicable permissions and restrictions.
- //
- //=============================================================================
- //-----------------------------------------------------------------------------
- // MiscTableScrollData.M
- //
- // The (DATA) category of MiscTableScroll. Implements the management
- // of the cells of the table.
- //
- //-----------------------------------------------------------------------------
- //-----------------------------------------------------------------------------
- // $Id: MiscTableScrollData.M,v 1.9 96/01/13 23:43:48 zarnuk Exp $
- // $Log: MiscTableScrollData.M,v $
- // Revision 1.9 96/01/13 23:43:48 zarnuk
- // Fixed bug: -lazyCellAt:: was not asking the dataDelegate.
- // Added value-At:: methods.
- // All allocations are now done from [self zone].
- //
- // Revision 1.8 95/10/20 00:13:00 sunshine
- // Was including MiscTableScroll.h and MiscTableCell.h with "" instead of <>.
- //
- // Revision 1.7 95/10/14 16:50:58 zarnuk
- // Fixed bug: -renewRows: was getting the prototype from the wrong slot.
- //
- // Revision 1.6 95/10/08 16:13:38 zarnuk
- // Cell* --> id.
- //-----------------------------------------------------------------------------
- #import <misckit/MiscTableScroll.h>
- #import <misckit/MiscTableCell.h>
- #import "MiscTableBorder.h"
- extern "Objective-C" {
- #import <appkit/Cell.h>
- }
- extern "C" {
- #import <assert.h>
- #import <limits.h>
- #import <stdlib.h>
- #import <string.h>
- }
-
- @implementation MiscTableScroll(DATA)
-
- //-----------------------------------------------------------------------------
- // - dummyCellAt::
- //-----------------------------------------------------------------------------
- - dummyCellAt:(int)row :(int)col
- {
- id p = colInfo.border->getPrototype_P( col );
- [self retireCell:p at:row:col];
- [self reviveCell:p at:row:col];
- if ([p respondsTo: @selector(setStringValue:)])
- {
- char buff[64];
- sprintf( buff, "(r%d,c%d)", row, col );
- [p setStringValue:buff];
- }
- return p;
- }
-
-
- //-----------------------------------------------------------------------------
- // - lazyCellAt::
- //-----------------------------------------------------------------------------
- - lazyCellAt:(int)row :(int)col
- {
- if (delegate != 0 &&
- [delegate respondsTo: @selector(tableScroll:cellAt: :)])
- return [delegate tableScroll:self cellAt:row :col];
- if (dataDelegate != 0 &&
- [dataDelegate respondsTo: @selector(tableScroll:cellAt: :)])
- return [dataDelegate tableScroll:self cellAt:row :col];
- return 0;
- }
-
-
- //-----------------------------------------------------------------------------
- // - eagerCellAt::
- //-----------------------------------------------------------------------------
- - eagerCellAt:(int)row :(int)col
- {
- return cells[ row * num_cols + col ];
- }
-
-
- //-----------------------------------------------------------------------------
- // - cellAt::
- //-----------------------------------------------------------------------------
- - cellAt:(int)row :(int)col
- {
- id cell = 0;
- if ((unsigned int) row < (unsigned int) num_rows &&
- (unsigned int) col < (unsigned int) num_cols)
- {
- if (!lazy)
- cell = [self eagerCellAt:row:col];
- else if (![self respondsTo: @selector(isInIB)])
- cell = [self lazyCellAt:row:col];
- else
- cell = [self dummyCellAt:row:col];
-
- MiscCoord_V vRow = rowInfo.border->physicalToVisual(row);
- MiscCoord_V vCol = colInfo.border->physicalToVisual(col);
- if ([cell respondsTo:@selector(setState:)])
- [cell setState: colInfo.border->selectionSet().contains(vCol) ||
- rowInfo.border->selectionSet().contains(vRow)];
- }
- return cell;
- }
-
-
- //-----------------------------------------------------------------------------
- // tagAt::, intValueAt::, floatValueAt::, doubleValueAt::,
- // stringValueAt::, titleAt::, stateAt::
- //-----------------------------------------------------------------------------
- #define MISC_CELL_VAL( DATA_TYPE, NAME )\
- - (DATA_TYPE) NAME##At:(int) r :(int) c\
- {\
- if (lazy)\
- {\
- if (delegate != 0 &&\
- [delegate respondsTo:@selector(tableScroll:NAME##At: :)])\
- return [delegate tableScroll:self NAME##At:r:c];\
- if (dataDelegate != 0 &&\
- [dataDelegate respondsTo:@selector(tableScroll:NAME##At: :)])\
- return [dataDelegate tableScroll:self NAME##At:r:c];\
- }\
- id cell = [self cellAt:r:c];\
- if (cell != 0 && [cell respondsTo:@selector(NAME)])\
- return [cell NAME];\
- return 0;\
- }
-
- MISC_CELL_VAL( int, tag ) // tagAt::
- MISC_CELL_VAL( int, intValue ) // intValueAt::
- MISC_CELL_VAL( float, floatValue ) // floatValueAt::
- MISC_CELL_VAL( double, doubleValue ) // doubleValueAt::
- MISC_CELL_VAL( char const*, stringValue ) // stringValueAt::
- MISC_CELL_VAL( int, state ) // stateAt::
- MISC_CELL_VAL( char const*, title ) // titleAt::
- #undef MISC_CELL_VAL
-
-
- //-----------------------------------------------------------------------------
- // - buffCount
- // For lazy-mode tables that perform multiple-buffering. This can
- // avoid copying when accessing more than one cell at a time (such
- // as during sorting.)
- //-----------------------------------------------------------------------------
- - (int) buffCount
- {
- if (delegate != 0 &&
- [delegate respondsTo:@selector(tableScrollBuffCount:)])
- return [delegate tableScrollBuffCount:self];
- if (dataDelegate != 0 &&
- [dataDelegate respondsTo:@selector(tableScrollBuffCount:)])
- return [dataDelegate tableScrollBuffCount:self];
- return 1;
- }
-
-
- //-----------------------------------------------------------------------------
- // - expandIfNeeded
- //-----------------------------------------------------------------------------
- - (void) expandIfNeeded
- {
- int const num_cells = max_rows * num_cols;
- if (num_cells > max_cells)
- {
- NXZone* const z = [self zone];
- int const nbytes = num_cells * sizeof(*cells);
- if (max_cells == 0)
- cells = (id*) NXZoneMalloc( z, nbytes );
- else
- cells = (id*) NXZoneRealloc( z, cells, nbytes );
- max_cells = num_cells;
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - lazyInsertColAt:
- //-----------------------------------------------------------------------------
- - (void) lazyInsertColAt:(int)n
- {
- colInfo.border->insertAt(n,n); // FIXME: Check this.
- num_cols++;
- }
-
-
- //-----------------------------------------------------------------------------
- // - eagerInsertColAt:
- //-----------------------------------------------------------------------------
- - (void) eagerInsertColAt:(int)n
- {
- assert( 0 <= n ); assert( n <= num_cols );
- assert( 0 < num_cols ); // lazyInsert must increment num_cols.
-
- if (max_rows > 0 || num_rows > 0)
- {
- if (max_rows == 0)
- max_rows = num_rows;
- [self expandIfNeeded];
- int const num_new = num_cols;
- int const num_old = num_cols - 1;
- if (num_old > 0) // Shift old, existing cells.
- {
- int const frag = num_old - n; // #cols right of insert col.
- id* src = cells + (max_rows * num_old) - frag;
- id* dst = cells + (max_rows * num_new) - frag;
- if (frag > 0) // Last partial row.
- memmove( dst, src, frag * sizeof(*dst) );
-
- int const nbytes = num_old * sizeof(*dst);
- src -= num_old;
- dst -= num_new;
- while (src > cells) // All full rows.
- {
- memmove( dst, src, nbytes );
- src -= num_old;
- dst -= num_new;
- }
- }
- int row = 0;
- id const proto = colInfo.border->getPrototype_P(n);
- id* const plim = cells + (max_rows * num_new);
- id* p = cells + n;
- while (p < plim) // Initialize cells in new column.
- {
- *p = [self reviveCell:[proto copy] at:row++ :n];
- p += num_new;
- }
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - insertColAt:
- //-----------------------------------------------------------------------------
- - insertColAt:(int)n
- {
- if (0 <= n && n <= num_cols)
- {
- [self lazyInsertColAt:n];
- if (!lazy)
- [self eagerInsertColAt:n];
- [self constrainSize];
- [self update];
- return self;
- }
- return 0;
- }
-
-
- //-----------------------------------------------------------------------------
- // - addCol
- //-----------------------------------------------------------------------------
- - addCol
- {
- return [self insertColAt: num_cols];
- }
-
-
- //-----------------------------------------------------------------------------
- // - lazyDeleteColAt:
- //-----------------------------------------------------------------------------
- - (void) lazyDeleteColAt:(int)n
- {
- colInfo.border->deleteAt_P(n);
- num_cols--;
- }
-
-
- //-----------------------------------------------------------------------------
- // - eagerDeleteColAt:
- //-----------------------------------------------------------------------------
- - (void) eagerDeleteColAt:(int)n
- {
- assert( 0 < num_cols );
- assert( 0 <= n ); assert( n < num_cols );
- if (max_rows > 0)
- {
- int const num_old = num_cols;
- int const num_new = num_cols - 1;
- id* dst = cells + n;
- id* src = dst + 1;
- id* const dst_lim = cells + (num_old * max_rows);
- while (dst < dst_lim) // Destroy deleted cells.
- {
- [*dst free];
- dst += num_old;
- }
- if (num_new > 0) // Shift remaining columns.
- {
- dst = cells + n;
- int const nbytes = num_new * sizeof(*dst);
- id* const src_lim = cells + (max_rows - 1) * num_old + n;
- while (src < src_lim)
- {
- memmove( dst, src, nbytes );
- dst += num_new;
- src += num_old;
- }
- if (n < num_new) // Shift last partial row.
- memmove( dst, src, (num_new - n) * sizeof(*dst) );
- }
- else // (num_new <= 0)
- {
- max_rows = 0;
- }
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - deleteColAt:
- //-----------------------------------------------------------------------------
- - deleteColAt:(int)n
- {
- if (0 <= n && n < num_cols)
- {
- if (!lazy)
- [self eagerDeleteColAt:n];
- [self lazyDeleteColAt:n];
- [self constrainSize];
- [self update];
- return self;
- }
- return 0;
- }
-
-
- //-----------------------------------------------------------------------------
- // - numCols
- //-----------------------------------------------------------------------------
- - (int) numCols
- {
- return num_cols;
- }
-
-
- //-----------------------------------------------------------------------------
- // - lazyInsertRowAt:
- //-----------------------------------------------------------------------------
- - (void) lazyInsertRowAt:(int)n
- {
- rowInfo.border->insertAt(n,n); // FIXME. Check this.
- num_rows++;
- }
-
-
- //-----------------------------------------------------------------------------
- // - eagerInsertRowAt:
- //-----------------------------------------------------------------------------
- - (void) eagerInsertRowAt:(int)n
- {
- assert( 0 < num_rows ); // lazy-insert must increment num_rows
- assert( 0 <= n ); assert( n < num_rows );
-
- if (num_cols > 0)
- {
- max_rows++; // Incremental growth.
- assert( num_rows <= max_rows );
- [self expandIfNeeded];
-
- int const old_max = max_rows - 1;
- id* p = cells + n * num_cols;
- if (n < old_max) // Shift other rows.
- {
- id* src = p;
- id* dst = src + num_cols;
- memmove( dst, src, (old_max - n) * num_cols * sizeof(*dst) );
- }
- MiscTableBorder* const bp = colInfo.border;
- for (int c = 0; c < num_cols; c++) // Initialize new cells.
- *p++ = [self reviveCell:[bp->getPrototype_P(c) copy] at:n :c];
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - insertRowAt:
- //-----------------------------------------------------------------------------
- - insertRowAt:(int)n
- {
- if (0 <= n && n <= num_rows)
- {
- [self lazyInsertRowAt:n];
- if (!lazy)
- [self eagerInsertRowAt:n];
- [self constrainSize];
- [self update];
- return self;
- }
- return 0;
- }
-
-
- //-----------------------------------------------------------------------------
- // - eagerAddRow
- //
- // NOTE *1*
- // We always initialize new rows when they are created, so if num_rows
- // is less than max_rows, the new row has already been initialized.
- //
- // NOTE *2*
- // The initialization loop is organized in column-major order because
- // we want to maximize locality of reference for both code and data
- // during the -copy calls.
- //-----------------------------------------------------------------------------
- - (void) eagerAddRow
- {
- assert( 0 < num_rows ); // lazy insertRowAt: must increment num_rows.
- if (num_cols > 0)
- {
- if (num_rows >= max_rows) // NOTE *1*
- {
- int const MISC_TS_MAX_ROWS = ((INT_MAX >> 1) + 1);
- assert( num_rows <= MISC_TS_MAX_ROWS );
-
- int const old_max = max_rows;
- int n = ( max_rows ? max_rows : 16 );
- while (n < num_rows)
- n <<= 1;
- int const new_max = max_rows = n;
-
- [self expandIfNeeded];
- id* p0 = cells + old_max * num_cols;
- for (int c = 0; c < num_cols; c++) // NOTE *2*
- {
- id const proto = colInfo.border->getPrototype_P(c);
- id* p = p0++;
- id* const plim = p + (new_max - old_max) * num_cols;
- while (p < plim)
- {
- *p = [proto copy]; // Initialize new cells.
- p += num_cols;
- }
- }
- }
- int const row = num_rows - 1;
- id* p = cells + (num_cols * row);
- for (int col = 0; col < num_cols; col++)
- *p++ = [self reviveCell:*p at:row :col];
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - addRow
- //
- // NOTE: We explicitly do NOT -constrainSize and -update here, because we
- // expect that the user will call this routine many times successively.
- //-----------------------------------------------------------------------------
- - addRow
- {
- [self lazyInsertRowAt:num_rows];
- if (!lazy)
- [self eagerAddRow];
- return self;
- }
-
-
- //-----------------------------------------------------------------------------
- // - lazyDeleteRowAt:
- //-----------------------------------------------------------------------------
- - (void) lazyDeleteRowAt:(int)n
- {
- rowInfo.border->deleteAt_P(n);
- num_rows--;
- }
-
-
- //-----------------------------------------------------------------------------
- // - eagerDeleteRowAt:
- //-----------------------------------------------------------------------------
- - (void) eagerDeleteRowAt:(int)n
- {
- assert( 0 < num_rows );
- assert( 0 <= n ); assert( n < num_rows );
- if (num_cols > 0)
- {
- assert( num_rows <= max_rows );
- max_rows--;
- id* const dst = cells + (n * num_cols );
- id* p = dst;
- id* const plim = p + num_cols;
- while (p < plim) // Destroy the cells.
- {
- [*p free];
- p++;
- }
- if (n < max_rows)
- memmove( dst, plim, (max_rows - n) * num_cols * sizeof(*dst) );
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - deleteRowAt:
- //-----------------------------------------------------------------------------
- - deleteRowAt:(int)n
- {
- if (0 <= n && n < num_rows)
- {
- if (!lazy)
- [self eagerDeleteRowAt:n];
- [self lazyDeleteRowAt:n];
- [self constrainSize];
- [self update];
- return self;
- }
- return 0;
- }
-
-
- //-----------------------------------------------------------------------------
- // - numRows
- //-----------------------------------------------------------------------------
- - (int) numRows
- {
- return num_rows;
- }
-
-
- //-----------------------------------------------------------------------------
- // - lazyRenewRows:
- //-----------------------------------------------------------------------------
- - (void) lazyRenewRows:(int)n
- {
- rowInfo.border->setCount(n);
- num_rows = n;
- }
-
-
- //-----------------------------------------------------------------------------
- // - eagerRenewRows:
- //
- // NOTE *1*
- // Since we initialize all cells when they are allocated, we only have
- // to do extra work if we need to allocate more rows.
- //
- // NOTE *2*
- // The initialization loop is organized in column-major order to
- // increase locality of reference for both code and data during the
- // call to -copy.
- //-----------------------------------------------------------------------------
- - (void) eagerRenewRows:(int)n
- {
- assert( 0 <= n );
- if (num_cols > 0)
- {
- int const old_num_rows = num_rows;
- int const new_num_rows = n;
- if (n > max_rows) // NOTE *1*
- {
- int const max_old = max_rows;
- int const max_new = max_rows = n;
- [self expandIfNeeded];
- id* p0 = cells + max_old * num_cols;
- id* const plim = cells + max_new * num_cols;
- for (int c = 0; c < num_cols; c++) // NOTE *2*
- {
- id* p = p0++;
- id const proto = colInfo.border->getPrototype_P(c);
- while (p < plim)
- {
- *p = [proto copy];
- p += num_cols;
- }
- }
- }
- if (old_num_rows < new_num_rows) // Growing
- {
- id* p0 = cells + old_num_rows * num_cols;
- id* const plim = cells + new_num_rows * num_cols;
- for (int c = 0; c < num_cols; c++) // NOTE *2*
- {
- int r = old_num_rows;
- id* p = p0++;
- while (p < plim)
- {
- *p = [self reviveCell:*p at:r++ :c];
- p += num_cols;
- }
- }
- }
- else if (old_num_rows > new_num_rows) // Shrinking
- {
- id* p0 = cells + new_num_rows * num_cols;
- id* const plim = cells + old_num_rows * num_cols;
- for (int c = 0; c < num_cols; c++) // NOTE *2*
- {
- int r = new_num_rows;
- id* p = p0++;
- while (p < plim)
- {
- *p = [self retireCell:*p at:r++ :c];
- p += num_cols;
- }
- }
- }
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - renewRows:
- //-----------------------------------------------------------------------------
- - renewRows:(int)n
- {
- [self clearSelection];
- if (0 <= n && n != num_rows)
- {
- if (!lazy)
- [self eagerRenewRows:n];
- [self lazyRenewRows:n];
- }
- [self constrainSize];
- [self update];
- return self;
- }
-
-
- //-----------------------------------------------------------------------------
- // - empty
- //-----------------------------------------------------------------------------
- - empty
- {
- return [self renewRows:0];
- }
-
-
- //-----------------------------------------------------------------------------
- // - freeCells
- //-----------------------------------------------------------------------------
- - (void) freeCells
- {
- if (max_rows > 0 && num_cols > 0)
- {
- id* p0 = cells;
- for (int c = 0; c < num_cols; c++)
- {
- id* p = p0++;
- for (int r = 0; r < max_rows; r++)
- {
- [*p free];
- p += num_cols;
- }
- }
- }
- if (cells != 0)
- NXZoneFree( [self zone], cells );
- cells = 0;
- max_cells = 0;
- max_rows = 0;
- }
-
-
- //-----------------------------------------------------------------------------
- // - emptyAndFreeCells
- //-----------------------------------------------------------------------------
- - emptyAndFreeCells
- {
- [self empty];
- [self freeCells];
- return self;
- }
-
-
- //-----------------------------------------------------------------------------
- // - setLazy:
- //-----------------------------------------------------------------------------
- - (void) setLazy:(BOOL)flag
- {
- if (lazy != flag)
- {
- lazy = flag;
- if (lazy)
- [self freeCells];
- else
- [self eagerRenewRows:num_rows];
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - isLazy
- //-----------------------------------------------------------------------------
- - (BOOL) isLazy
- {
- return lazy;
- }
-
-
- //-----------------------------------------------------------------------------
- // Generic Slot methods
- //-----------------------------------------------------------------------------
- - addSlot:(MiscBorderType)b
- { return (b == MISC_COL_BORDER) ? [self addCol] : [self addRow]; }
-
- - border:(MiscBorderType)b insertSlotAt:(int)n
- { return (b == MISC_COL_BORDER) ?
- [self insertColAt:n] : [self insertRowAt:n]; }
-
- - border:(MiscBorderType)b deleteSlotAt:(int)n
- { return (b == MISC_COL_BORDER) ?
- [self deleteColAt:n] : [self deleteRowAt:n]; }
-
- - (int) numSlots:(MiscBorderType)b
- { return (b == MISC_COL_BORDER) ? [self numCols] : [self numRows]; }
-
-
- //-----------------------------------------------------------------------------
- // REVIVE
- //-----------------------------------------------------------------------------
- - doReviveCell:cell at:(int)row:(int)col
- {
- if (cell != 0)
- {
- if ([cell respondsTo:@selector(setOwner:)])
- [cell setOwner:self];
-
- if ([cell respondsTo:@selector(setUseOwnerFont:)])
- [cell setUseOwnerFont:YES];
- if ([cell respondsTo:@selector(setUseOwnerTextColor:)])
- [cell setUseOwnerTextColor:YES];
- if ([cell respondsTo:@selector(setUseOwnerBackgroundColor:)])
- [cell setUseOwnerBackgroundColor:YES];
- if ([cell respondsTo:@selector(setUseOwnerHighlightTextColor:)])
- [cell setUseOwnerHighlightTextColor:YES];
- if ([cell respondsTo:@selector(setUseOwnerHighlightBackgroundColor:)])
- [cell setUseOwnerHighlightBackgroundColor:YES];
-
- if ([cell respondsTo:@selector(setOwnerFont:)])
- [cell setOwnerFont:[self font]];
- else if ([cell respondsTo:@selector(setFont:)])
- [cell setFont:[self font]];
-
- if ([cell respondsTo:@selector(setOwnerTextColor:)])
- [cell setOwnerTextColor:[self textColor]];
- else if ([cell respondsTo:@selector(setTextColor:)])
- [cell setTextColor:[self textColor]];
-
- if ([cell respondsTo:@selector(setOwnerBackgroundColor:)])
- [cell setOwnerBackgroundColor:[self backgroundColor]];
- else if ([cell respondsTo:@selector(setBackgroundColor:)])
- [cell setBackgroundColor:[self backgroundColor]];
-
- if ([cell respondsTo:@selector(setOwnerHighlightTextColor:)])
- [cell setOwnerHighlightTextColor:[self highlightTextColor]];
- else if ([cell respondsTo:@selector(setHighlightTextColor:)])
- [cell setHighlightTextColor:[self highlightTextColor]];
-
- if ([cell respondsTo:@selector(setOwnerHighlightBackgroundColor:)])
- [cell setOwnerHighlightBackgroundColor:
- [self highlightBackgroundColor]];
- else if ([cell respondsTo:@selector(setHighlightBackgroundColor:)])
- [cell setHighlightBackgroundColor:[self highlightBackgroundColor]];
- }
- return cell;
- }
-
-
- - reviveCell:cell at:(int)row :(int)col
- {
- if (delegate != 0 &&
- [delegate respondsTo:@selector(tableScroll:reviveCell:at: :)])
- return [delegate tableScroll:self reviveCell:cell at:row :col];
-
- if (dataDelegate != 0 &&
- [dataDelegate respondsTo:@selector(tableScroll:reviveCell:at: :)])
- return [dataDelegate tableScroll:self reviveCell:cell at:row :col];
-
- if (cell != 0 && [cell respondsTo:@selector(tableScroll:reviveAt: :)])
- return [cell tableScroll:self reviveAt:row :col];
-
- return [self doReviveCell:cell at:row :col];
- }
-
-
- //-----------------------------------------------------------------------------
- // RETIRE
- //-----------------------------------------------------------------------------
- - doRetireCell:cell at:(int)row:(int)col
- {
- if ([cell respondsTo:@selector(type)] && [cell type] == NX_ICONCELL)
- [cell setIcon:0];
- else if ([cell respondsTo:@selector(setTitle:)])
- [cell setTitle:""];
- else if ([cell respondsTo:@selector(setStringValueNoCopy:)])
- [cell setStringValueNoCopy:""];
- else if ([cell respondsTo:@selector(setStringValue:)])
- [cell setStringValue:""];
- return cell;
- }
-
-
- - retireCell:cell at:(int)row:(int)col
- {
- if (delegate != 0 &&
- [delegate respondsTo:@selector(tableScroll:retireCell:at: :)])
- return [delegate tableScroll:self retireCell:cell at:row :col];
-
- if (dataDelegate != 0 &&
- [dataDelegate respondsTo:@selector(tableScroll:retireCell:at: :)])
- return [dataDelegate tableScroll:self retireCell:cell at:row :col];
-
- if (cell != 0 && [cell respondsTo:@selector(tableScroll:retireAt: :)])
- return [cell tableScroll:self retireAt:row :col];
-
- return [self doRetireCell:cell at:row :col];
- }
-
- @end
-