Proxy Data Source for Table with Expanders

Description: creating a proxy data source for data grid. The previous stage is creating a data source.

The ProxyDataSource.h File

#import <NuGridView/NuGridCellCache.h>
#import <NuGridView/NuGridCellStyle.h>
#import <NuGridView/NuGridView.h>
#import <NuGridView/NuGridProxyDataSource.h>
#import "DataSource.h"
@interface ProxyDataSource : NSObject<NuGridProxyDataSource> {
    DataSource *_dataSource; // Link to data source
    NSMutableDictionary *styles; // Array of styles
    NSMutableArray *updateObserver; // Array of observers
    id<NuGridCellCache> cellCacheProvider; // Table cache provider
}
// Returns style for specified cell
- (NuGridCellStyle *)gridView:(NuGridView *)gridView getStyleForCellInRow:(NSInteger)rowNumber column:(NSInteger)columnNumber;
@end

The ProxyDataSource.m File

#import &quot;ProxyDataSource.h&quot;
#import &lt;NuGridView/NuGridUpdateObserver.h&gt;
#import &lt;NuGridView/NuGridExpandableCell.h&gt;
#import &lt;NuGridView/NuGridDataSource.h&gt;
#import &lt;NuGridView/NuGridCell.h&gt;
#import &quot;GridRow.h&quot;
@implementation ProxyDataSource
- (id) init
{
    self = [super init];
    if(self)
    {
        _dataSource = nil;
        styles = [NSMutableDictionary new];
        updateObserver = [NSMutableArray new];
        return self;
    }
    return nil;
}
// Returns data source
- (id&lt;NuGridDataSource&gt;)dataSource
{
    return _dataSource;
}
// Sets data source
- (void)setDataSource:(id&lt;NuGridDataSource&gt;)dataSource
{
    _dataSource = dataSource;
    // Set table cache provider
    if ([self.dataSource respondsToSelector:@selector(registerCellCacheProvider:)]) {
        [self.dataSource registerCellCacheProvider:cellCacheProvider];
    }
}
// Adds observer into corresponding array of observers
- (void)addObserver:(id&lt;NuGridUpdateObserver&gt;)observer
{
    [updateObserver addObject:observer];
}
// Removes observer from corresponding array of observers
- (void)removeObserver:(id&lt;NuGridUpdateObserver&gt;)observer
{
    [updateObserver removeObject:observer];
}
- (void)beforeUpdate:(NSString *)key {
    for (id&lt;NuGridUpdateObserver&gt; observer in updateObserver) {
        [observer beforeUpdate:key];
    }
}
- (void)afterUpdate:(NSString*)key {
    for (id&lt;NuGridUpdateObserver&gt; observer in updateObserver) {
        [observer afterUpdate:key];
    }
}
// Returns whether row headers are in data source
- (BOOL)gridViewHasRowHeader:(NuGridView *)gridView
{
    return [_dataSource gridViewHasRowHeader:gridView];
}
// Returns whether columns are in data source
- (BOOL)gridViewHasColumnHeader:(NuGridView *)gridView
{
    return [_dataSource gridViewHasColumnHeader:gridView];
}
// Returns the number of fixed table columns
- (NSInteger)gridViewFixedRowCount:(NuGridView *)gridView
{
    return 0;
}
// Returns the number of fixed table rows
- (NSInteger)gridViewFixedColumnCount:(NuGridView *)gridView
{
    return 0;
}
// Returns the number of table rows
- (NSInteger)gridViewRowCount:(NuGridView *)gridView
{
    return [_dataSource gridViewRowCount:gridView];
}
// Returns the number of table columns
- (NSInteger)gridViewColumnCount:(NuGridView *)gridView
{
    return [_dataSource gridViewColumnCount:gridView];
}
// Returns the number of header rows
- (NSInteger)gridViewRowHeaderCount:(NuGridView *)gridView
{
    return [_dataSource gridViewRowHeaderCount:gridView];
}
// Returns the number of header columns
- (NSInteger)gridViewColumnHeaderCount:(NuGridView *)gridView
{
    return [_dataSource gridViewColumnHeaderCount:gridView];
}
// Returns row index by its number
- (NSInteger)gridView:(NuGridView *)gridView rowIndexByNumber:(NSInteger)rowNumber
{
    return rowNumber;
}
// Returns column index by its number
- (NSInteger)gridView:(NuGridView *)gridView columnIndexByNumber:(NSInteger)columnNumber
{
    return columnNumber;
}
// Returns column number by its index
- (NSInteger)gridView:(NuGridView *)gridView columnNumberByIndex:(NSInteger)columnIndex
{
    return columnIndex;
}
// Returns row number by its index
- (NSInteger)gridView:(NuGridView *)gridView rowNumberByIndex:(NSInteger)rowIndex
{
    return rowIndex;
}
// Sets default style used
- (void) gridView:(NuGridView *)gridView setDefaultStyle:(NuGridCellStyle *)style
{
    [styles setValue:style forKey:@&quot;defStyle&quot;];
}
// Sets default style for column header
- (void) gridView:(NuGridView *)gridView setDefaultStyleForColumnHeader:(NuGridCellStyle *)style
{
    [styles setValue:style forKey:@&quot;defColumnHeaderStyle&quot;];
}
// Sets default style for row header
- (void) gridView:(NuGridView *)gridView setDefaultStyleForRowHeader:(NuGridCellStyle *)style
{
    [styles setValue:style forKey:@&quot;defRowHeaderStyle&quot;];
}
// Applies style to table cell
- (void)gridView:(NuGridView *)gridView applyStyleForCell:(NuGridCell *)cell
{
    if (cell.columnIndex&lt;0) {
        [cell applyStyle:[styles objectForKey:@&quot;defColumnHeaderStyle&quot;]];
    }
    else
    if (cell.rowIndex&lt;0) {
        [cell applyStyle:[styles objectForKey:@&quot;defRowHeaderStyle&quot;]];
    }
    else
    [cell applyStyle:[styles objectForKey:@&quot;defStyle&quot;]];
};
// Returns style for header row
-(NuGridCellStyle *)gridView:(NuGridView *)gridView getStyleForHeaderForRow:(NSInteger)rowNumber {
    return [styles valueForKey:@&quot;defRowHeaderStyle&quot;];
};
// Returns table cell style
- (NuGridCellStyle *)gridView:(NuGridView *)gridView getStyleForCellInRow:(NSInteger)rowNumber column:(NSInteger)columnNumber {
    if (columnNumber&lt;0) {
        return [styles valueForKey:@&quot;defColumnHeaderStyle&quot;];
    }
    else
    if (rowNumber&lt;0) {
        return [styles valueForKey:@&quot;defRowHeaderStyle&quot;];
    }
    else {
        return [styles valueForKey:@&quot;defStyle&quot;];
    }
}
// Returns cell by row number and column number
- (NuGridCell *) gridView:(NuGridView *)gridView cellInRow:(NSInteger)row inColumn:(NSInteger)column
{
    // Get cell from data source
    NuGridCell *cell=[_dataSource gridView:gridView cellInRow:row inColumn:column];
    // Apply style to this cell
    [self gridView:gridView applyStyleForCell:cell];
    return cell;
};
// Returns row header cell
- (NuGridCell *) gridView:(NuGridView *)gridView headerForRow:(NSInteger)row number:(NSInteger)number
{
    NuGridExpandableCell *cell = (NuGridExpandableCell *)[_dataSource gridView:gridView headerForRow:row number:number];
    [self gridView:gridView applyStyleForCell:cell];
    // Determine whether cell contains expander
    if([_dataSource gridView:gridView parentRowForRow:row] &gt; 0)
    {
        GridRow *gridRow = [[_dataSource data] objectAtIndex:row];
        [cell clearImages];
        // Specify that cell contains expander
        cell.isExpandableRow = YES;
        // Specify that cell reacts to touch
        cell.isExpandIconTouched = YES;
        if ([gridRow isExpanded]) {
            if ([gridView isRightToLeft]) {
                // Add expander icon
                [cell addImage:[[cell style] expandedImage]
                outputSize:CGSizeMake(10, 10)
                alignment:[[cell style] expanderImageAlignment] | NuImageHorizontalAlignmentRight
                zPosition:NuImageZOrderBack
                border:[[cell style] expanderImageMargin] * [gridRow level]
                key:@&quot;expand&quot;];
                [cell setIndent:[gridRow level]];
                } else {
                // Add expander icon
                [cell addImage:[[cell style] expandedImage]
                outputSize:CGSizeMake(10, 10)
                alignment:[[cell style] expanderImageAlignment]
                zPosition:NuImageZOrderBack
                border:[[cell style] expanderImageMargin] * [gridRow level]
                key:@&quot;expand&quot;];
            }
        }
        else {
            if ([gridView isRightToLeft]) {
                // Add expander icon
                [cell addImage:[[cell style] collapsedRTLImage]
                outputSize:CGSizeMake(10, 10)
                alignment:[[cell style] expanderImageAlignment] | NuImageHorizontalAlignmentRight
                zPosition:NuImageZOrderBack
                border:[[cell style] expanderImageMargin] * [gridRow level]
                key:@&quot;collapse&quot;];
                [cell setIndent:[gridRow level]];
                } else {
                // Add expander icon
                [cell addImage:[[cell style] collapsedImage]
                outputSize:CGSizeMake(10, 10)
                alignment:[[cell style] expanderImageAlignment]
                zPosition:NuImageZOrderBack
                border:[[cell style] expanderImageMargin] * [gridRow level]
                key:@&quot;collapse&quot;];
            }
        }
    }
    return cell;
}
// Returns column header cell
- (NuGridCell *) gridView:(NuGridView *)gridView headerForColumn:(NSInteger)column number:(NSInteger)number
{
    NuGridCell *cell = [_dataSource gridView:gridView headerForColumn:column number:number];
    [self gridView:gridView applyStyleForCell:cell];
    return cell;
}
// Returns left top table cell
- (NuGridCell *) gridView:(NuGridView *)gridView cornerCellInRowNumber:(NSInteger)rowNumber inColumnNumber:(NSInteger)columnNumber
{
    NuGridCell *cell = [_dataSource gridView:gridView cornerCellInRowNumber:rowNumber inColumnNumber:columnNumber];
    // Set style for specified table cell
    [self gridView:gridView applyStyleForCell:cell];
    return cell;
}
// Expands rows with specified number
- (void) gridView:(NuGridView *)gridView expandRow:(NSInteger)rowNumber
{
    [self beforeUpdate:@&quot;DataSource&quot;];
    // Check if this row can expand
    if([_dataSource gridView:gridView parentRowForRow:rowNumber] &gt; 0) {
        // Expand row
        [_dataSource expandRow:rowNumber];
    }
    // Refresh table
    [self afterUpdate:@&quot;DataSource&quot;];
}
// Collapses row with specified number
- (void) gridView:(NuGridView *)gridView collapseRow:(NSInteger)rowNumber
{
    [self beforeUpdate:@&quot;DataSource&quot;];
    // Check if this row can collapse
    if([_dataSource gridView:gridView parentRowForRow:rowNumber] &gt; 0)
    {
        // Collapse row
        [_dataSource collapseRow:rowNumber];
    }
    [self afterUpdate:@&quot;DataSource&quot;];
}
// Returns whether the specified column is fixed
- (BOOL)gridView:(NuGridView *)gridView isColumnWithIndexFixed:(NSInteger)columnIndex
{
    return NO;
}
// Returns whether the specified row is fixed
- (BOOL)gridView:(NuGridView *)gridView isRowWithIndexFixed:(NSInteger)rowIndex
{
    return NO;
}
// Sets table cache provider
- (void)registerCellCacheProvider:(id&lt;NuGridCellCache&gt;)cacheProvider {
    cellCacheProvider = cacheProvider;
    if (self.dataSource &amp;&amp; [self.dataSource respondsToSelector:@selector(registerCellCacheProvider:)]) {
        [self.dataSource registerCellCacheProvider:cellCacheProvider];
    }
}
@end

See also:

Creating a Table with Expanders