mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-25 11:31:02 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@6387 72102866-910b-0410-8b05-ffd578937521
1160 lines
23 KiB
Objective-C
1160 lines
23 KiB
Objective-C
/*
|
|
NSTableView.m
|
|
|
|
Copyright (C) 2000 Free Software Foundation, Inc.
|
|
|
|
Author: Nicola Pero <n.pero@mi.flashnet.it>
|
|
Date: March 2000
|
|
|
|
This file is part of the GNUstep GUI Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; see the file COPYING.LIB.
|
|
If not, write to the Free Software Foundation,
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#import <AppKit/NSTableView.h>
|
|
#import <AppKit/NSCell.h>
|
|
#import <AppKit/NSClipView.h>
|
|
#import <AppKit/NSColor.h>
|
|
#import <AppKit/NSGraphics.h>
|
|
#import <AppKit/NSScroller.h>
|
|
#import <AppKit/NSTableColumn.h>
|
|
#import <AppKit/NSTableHeaderView.h>
|
|
#import <AppKit/NSTextFieldCell.h>
|
|
#import <AppKit/PSOperators.h>
|
|
|
|
@interface GSTableCornerView : NSView
|
|
{}
|
|
@end
|
|
|
|
@implementation GSTableCornerView
|
|
|
|
- (void) drawRect: (NSRect)aRect
|
|
{
|
|
NSRect rect = _bounds;
|
|
|
|
NSDrawButton (rect, aRect);
|
|
[[NSColor controlShadowColor] set];
|
|
rect.size.width -= 4;
|
|
rect.size.height -= 4;
|
|
rect.origin.x += 2;
|
|
rect.origin.y += 2;
|
|
NSRectFill (rect);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation NSTableView
|
|
|
|
+ (void) initialize
|
|
{
|
|
if (self == [NSTableView class])
|
|
[self setVersion: 1];
|
|
}
|
|
|
|
/*
|
|
* Initializing/Releasing
|
|
*/
|
|
|
|
- (id) initWithFrame: (NSRect)frameRect
|
|
{
|
|
self = [super initWithFrame: frameRect];
|
|
_drawsGrid = YES;
|
|
_rowHeight = 16.0;
|
|
_intercellSpacing = NSMakeSize (2.0, 3.0);
|
|
ASSIGN (_gridColor, [NSColor gridColor]);
|
|
ASSIGN (_backgroundColor, [NSColor controlBackgroundColor]);
|
|
ASSIGN (_tableColumns, [NSMutableArray array]);
|
|
_headerView = [NSTableHeaderView new];
|
|
[_headerView setFrameSize: NSMakeSize (frameRect.size.width, 22.0)];
|
|
[_headerView setTableView: self];
|
|
_cornerView = [GSTableCornerView new];
|
|
[self tile];
|
|
return self;
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
TEST_RELEASE (_dataSource);
|
|
RELEASE (_gridColor);
|
|
RELEASE (_tableColumns);
|
|
TEST_RELEASE (_headerView);
|
|
TEST_RELEASE (_cornerView);
|
|
if (_numberOfColumns > 0)
|
|
{
|
|
NSZoneFree (NSDefaultMallocZone (), _columnOrigins);
|
|
}
|
|
[super dealloc];
|
|
}
|
|
|
|
- (BOOL) isFlipped
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
/*
|
|
* Table Dimensions
|
|
*/
|
|
|
|
- (int) numberOfColumns
|
|
{
|
|
return _numberOfColumns;
|
|
}
|
|
|
|
- (int) numberOfRows
|
|
{
|
|
return _numberOfRows;
|
|
}
|
|
|
|
/*
|
|
* Columns
|
|
*/
|
|
|
|
- (void) addTableColumn: (NSTableColumn *)aColumn
|
|
{
|
|
[aColumn setTableView: self];
|
|
[_tableColumns addObject: aColumn];
|
|
_numberOfColumns++;
|
|
if (_numberOfColumns > 1)
|
|
{
|
|
_columnOrigins = NSZoneRealloc (NSDefaultMallocZone (), _columnOrigins,
|
|
(sizeof (float)) * _numberOfColumns);
|
|
}
|
|
else
|
|
{
|
|
_columnOrigins = NSZoneMalloc (NSDefaultMallocZone (),
|
|
sizeof (float));
|
|
_columnOrigins = malloc (sizeof (float));
|
|
}
|
|
[self tile];
|
|
}
|
|
|
|
- (void) removeTableColumn: (NSTableColumn *)aColumn
|
|
{
|
|
int columnIndex = [self columnWithIdentifier: [aColumn identifier]];
|
|
|
|
if (columnIndex == -1)
|
|
{
|
|
NSLog (@"Warning: Tried to remove not-existent column from table");
|
|
return;
|
|
}
|
|
|
|
[_tableColumns removeObject: aColumn];
|
|
[aColumn setTableView: nil];
|
|
_numberOfColumns--;
|
|
if (_numberOfColumns > 0)
|
|
{
|
|
_columnOrigins = NSZoneRealloc (NSDefaultMallocZone (), _columnOrigins,
|
|
(sizeof (float)) * _numberOfColumns);
|
|
}
|
|
else
|
|
{
|
|
NSZoneFree (NSDefaultMallocZone (), _columnOrigins);
|
|
}
|
|
[self tile];
|
|
}
|
|
|
|
- (void) moveColumn: (int)columnIndex toColumn: (int)newIndex
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (NSArray *) tableColumns
|
|
{
|
|
return AUTORELEASE ([_tableColumns mutableCopyWithZone:
|
|
NSDefaultMallocZone ()]);
|
|
}
|
|
|
|
- (int) columnWithIdentifier: (id)anObject
|
|
{
|
|
NSEnumerator *enumerator = [_tableColumns objectEnumerator];
|
|
NSTableColumn *tb;
|
|
int return_value = 0;
|
|
|
|
while ((tb = [enumerator nextObject]) != nil)
|
|
{
|
|
if ([[tb identifier] isEqual: anObject])
|
|
return return_value;
|
|
else
|
|
return_value++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
- (NSTableColumn *) tableColumnWithIdentifier:(id)anObject
|
|
{
|
|
int indexOfColumn = [self columnWithIdentifier: anObject];
|
|
|
|
if (indexOfColumn == -1)
|
|
return nil;
|
|
else
|
|
return [_tableColumns objectAtIndex: indexOfColumn];
|
|
}
|
|
|
|
/*
|
|
* Data Source
|
|
*/
|
|
|
|
- (id) dataSource
|
|
{
|
|
return _dataSource;
|
|
}
|
|
|
|
- (void) setDataSource: (id)anObject
|
|
{
|
|
/* Used only for readability */
|
|
SEL sel_a = @selector (numberOfRowsInTableView:);
|
|
SEL sel_b = @selector (tableView:objectValueForTableColumn:row:);
|
|
|
|
if ([anObject respondsToSelector: sel_a] == NO)
|
|
{
|
|
[NSException
|
|
raise: NSInternalInconsistencyException
|
|
format: @"Data Source doesn't respond to numberOfRowsInTableView:"];
|
|
}
|
|
|
|
if ([anObject respondsToSelector: sel_b] == NO)
|
|
{
|
|
[NSException
|
|
raise: NSInternalInconsistencyException
|
|
format: @"Data Source doesn't respond to tableView:objectValueForTableColumn:row:"];
|
|
}
|
|
|
|
ASSIGN (_dataSource, anObject);
|
|
[self tile];
|
|
[self reloadData];
|
|
}
|
|
|
|
/*
|
|
* Loading data
|
|
*/
|
|
|
|
- (void) reloadData
|
|
{
|
|
[self noteNumberOfRowsChanged];
|
|
[self setNeedsDisplay: YES];
|
|
}
|
|
|
|
/*
|
|
* Target-action
|
|
*/
|
|
|
|
- (void) setDoubleAction: (SEL)aSelector
|
|
{
|
|
// TODO - implement this in mouseDown:
|
|
_doubleAction = aSelector;
|
|
}
|
|
|
|
- (SEL) doubleAction
|
|
{
|
|
return _doubleAction;
|
|
}
|
|
|
|
- (int) clickedColumn
|
|
{
|
|
// TODO
|
|
return -1;
|
|
}
|
|
|
|
- (int) clickedRow
|
|
{
|
|
// TODO
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
*Configuration
|
|
*/
|
|
|
|
- (void) setAllowsColumnReordering: (BOOL)flag
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (BOOL) allowsColumnReordering
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
- (void) setAllowsColumnResizing: (BOOL)flag
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (BOOL) allowsColumnResizing
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
- (void) setAllowsMultipleSelection: (BOOL)flag
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (BOOL) allowsMultipleSelection
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
- (void) setAllowsEmptySelection: (BOOL)flag
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (BOOL) allowsEmptySelection
|
|
{
|
|
// TODO
|
|
return YES;
|
|
}
|
|
|
|
- (void) setAllowsColumnSelection: (BOOL)flag
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (BOOL) allowsColumnSelection
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
/*
|
|
* Drawing Attributes
|
|
*/
|
|
|
|
- (void) setIntercellSpacing: (NSSize)aSize
|
|
{
|
|
_intercellSpacing = aSize;
|
|
[self setNeedsDisplay: YES];
|
|
}
|
|
|
|
- (NSSize) intercellSpacing
|
|
{
|
|
return _intercellSpacing;
|
|
}
|
|
|
|
- (void) setRowHeight: (float)rowHeight
|
|
{
|
|
_rowHeight = rowHeight;
|
|
[self tile];
|
|
}
|
|
|
|
- (float) rowHeight
|
|
{
|
|
return _rowHeight;
|
|
}
|
|
|
|
- (void) setBackgroundColor: (NSColor *)aColor
|
|
{
|
|
ASSIGN (_backgroundColor, aColor);
|
|
}
|
|
|
|
- (NSColor *) backgroundColor
|
|
{
|
|
return _backgroundColor;
|
|
}
|
|
|
|
/*
|
|
* Selecting Columns and Rows
|
|
*/
|
|
- (void) selectColumn: (int) columnIndex
|
|
byExtendingSelection: (BOOL) flag
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (void) selectRow: (int) rowIndex
|
|
byExtendingSelection: (BOOL) flag
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (void) deselectColumn: (int) columnIndex
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (void) deselectRow: (int) rowIndex
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (int) numberOfSelectedColumns
|
|
{
|
|
// TODO
|
|
return 0;
|
|
}
|
|
|
|
- (int) numberOfSelectedRows
|
|
{
|
|
// TODO
|
|
return 0;
|
|
}
|
|
|
|
- (int) selectedColumn
|
|
{
|
|
// TODO
|
|
return -1;
|
|
}
|
|
|
|
- (int) selectedRow
|
|
{
|
|
// TODO
|
|
return -1;
|
|
}
|
|
|
|
- (BOOL) isColumnSelected: (int) columnIndex
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL) isRowSelected: (int) rowIndex
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
- (NSEnumerator *) selectedColumnEnumerator
|
|
{
|
|
// TODO
|
|
return nil;
|
|
}
|
|
|
|
- (NSEnumerator *) selectedRowEnumerator
|
|
{
|
|
// TODO
|
|
return nil;
|
|
}
|
|
|
|
- (void) selectAll: (id) sender
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (void) deselectAll: (id) sender
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Grid Drawing attributes
|
|
*/
|
|
|
|
- (void) setDrawsGrid: (BOOL)flag
|
|
{
|
|
_drawsGrid = flag;
|
|
}
|
|
|
|
- (BOOL) drawsGrid
|
|
{
|
|
return _drawsGrid;
|
|
}
|
|
|
|
- (void) setGridColor: (NSColor *)aColor
|
|
{
|
|
ASSIGN (_gridColor, aColor);
|
|
}
|
|
|
|
- (NSColor *) gridColor
|
|
{
|
|
return _gridColor;
|
|
}
|
|
|
|
/*
|
|
* Editing Cells
|
|
*/
|
|
|
|
- (void) editColumn: (int) columnIndex
|
|
row: (int) rowIndex
|
|
withEvent: (NSEvent *) theEvent
|
|
select: (BOOL) flag
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (int) editedRow
|
|
{
|
|
// TODO
|
|
return -1;
|
|
}
|
|
|
|
- (int) editedColumn
|
|
{
|
|
// TODO
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Auxiliary Components
|
|
*/
|
|
|
|
- (void) setHeaderView: (NSTableHeaderView*)aHeaderView
|
|
{
|
|
if (_super_view != nil)
|
|
{
|
|
/* Changing the headerView after the table has been linked to a scrollview
|
|
is not yet supported - the doc is not clear whether it should be supported
|
|
at all. If it is, perhaps it's going to be done through a private method
|
|
between the tableview and the scrollview. */
|
|
NSLog (@"setHeaderView: called after NSTableView has been put in the view tree!");
|
|
}
|
|
[_headerView setTableView: nil];
|
|
ASSIGN (_headerView, aHeaderView);
|
|
[_headerView setTableView: self];
|
|
[self tile];
|
|
}
|
|
|
|
- (NSTableHeaderView*) headerView
|
|
{
|
|
return _headerView;
|
|
}
|
|
|
|
- (void) setCornerView: (NSView*)aView
|
|
{
|
|
ASSIGN (_cornerView, aView);
|
|
[self tile];
|
|
}
|
|
|
|
- (NSView*) cornerView
|
|
{
|
|
return _cornerView;
|
|
}
|
|
|
|
/*
|
|
* Layout
|
|
*/
|
|
|
|
- (NSRect) rectOfColumn: (int)columnIndex
|
|
{
|
|
NSRect rect;
|
|
|
|
if (columnIndex < 0)
|
|
{
|
|
[NSException
|
|
raise: NSInternalInconsistencyException
|
|
format: @"ColumnIndex < 0 in [NSTableView -rectOfColumn:]"];
|
|
}
|
|
if (columnIndex >= _numberOfColumns)
|
|
{
|
|
[NSException
|
|
raise: NSInternalInconsistencyException
|
|
format: @"ColumnIndex => _numberOfColumns in [NSTableView -rectOfColumn:]"];
|
|
}
|
|
|
|
rect.origin.x = _columnOrigins[columnIndex];
|
|
rect.origin.y = _bounds.origin.y;
|
|
rect.size.width = [[_tableColumns objectAtIndex: columnIndex] width];
|
|
rect.size.height = _bounds.size.height;
|
|
return rect;
|
|
}
|
|
|
|
- (NSRect) rectOfRow: (int)rowIndex
|
|
{
|
|
NSRect rect;
|
|
|
|
if (rowIndex < 0)
|
|
{
|
|
[NSException
|
|
raise: NSInternalInconsistencyException
|
|
format: @"RowIndex < 0 in [NSTableView -rectOfRow:]"];
|
|
}
|
|
if (rowIndex >= _numberOfRows)
|
|
{
|
|
[NSException
|
|
raise: NSInternalInconsistencyException
|
|
format: @"RowIndex => _numberOfRows in [NSTableView -rectOfRow:]"];
|
|
}
|
|
rect.origin.x = _bounds.origin.x;
|
|
rect.origin.y = _bounds.origin.y + (_rowHeight * rowIndex);
|
|
rect.size.width = _bounds.size.width;
|
|
rect.size.height = _rowHeight;
|
|
return rect;
|
|
}
|
|
|
|
- (NSRange) columnsInRect: (NSRect)aRect
|
|
{
|
|
NSRange range;
|
|
|
|
range.location = [self columnAtPoint: aRect.origin];
|
|
range.length = [self columnAtPoint:
|
|
NSMakePoint (NSMaxX (aRect), _bounds.origin.y)];
|
|
range.length -= range.location;
|
|
range.length += 1;
|
|
return range;
|
|
}
|
|
|
|
- (NSRange) rowsInRect: (NSRect)aRect
|
|
{
|
|
NSRange range;
|
|
|
|
range.location = [self rowAtPoint: aRect.origin];
|
|
range.length = [self rowAtPoint:
|
|
NSMakePoint (_bounds.origin.x, NSMaxY (aRect))];
|
|
range.length -= range.location;
|
|
range.length += 1;
|
|
return range;
|
|
}
|
|
|
|
- (int) columnAtPoint: (NSPoint)aPoint
|
|
{
|
|
if ((NSMouseInRect (aPoint, _bounds, YES)) == NO)
|
|
return -1;
|
|
else
|
|
{
|
|
int i = 0;
|
|
|
|
while ((aPoint.x < _columnOrigins[i]) && (i < _numberOfColumns))
|
|
{
|
|
i++;
|
|
}
|
|
return i - 1;
|
|
}
|
|
}
|
|
|
|
- (int) rowAtPoint: (NSPoint)aPoint
|
|
{
|
|
/* NB: Y coordinate system is flipped in NSTableView */
|
|
if ((NSMouseInRect (aPoint, _bounds, YES)) == NO)
|
|
return -1;
|
|
else
|
|
{
|
|
int return_value;
|
|
|
|
aPoint.y -= _bounds.origin.y;
|
|
return_value = (int) (aPoint.y / _rowHeight);
|
|
/* This could happen if point lies on the grid line below the last row */
|
|
if (return_value == _numberOfRows)
|
|
{
|
|
return_value--;
|
|
}
|
|
return return_value;
|
|
}
|
|
}
|
|
|
|
- (NSRect) frameOfCellAtColumn: (int)columnIndex
|
|
row: (int)rowIndex
|
|
{
|
|
NSRect frameRect;
|
|
|
|
if ((columnIndex < 0)
|
|
|| (rowIndex < 0)
|
|
|| (columnIndex > (_numberOfColumns - 1))
|
|
|| (rowIndex > (_numberOfRows - 1)))
|
|
return NSZeroRect;
|
|
|
|
frameRect.origin.y = _bounds.origin.y + (rowIndex * _rowHeight);
|
|
frameRect.origin.y += _intercellSpacing.height / 2;
|
|
frameRect.size.height = _rowHeight - _intercellSpacing.height;
|
|
|
|
frameRect.origin.x = _columnOrigins[columnIndex];
|
|
frameRect.origin.x += _intercellSpacing.width / 2;
|
|
frameRect.size.width = [[_tableColumns objectAtIndex: columnIndex] width];
|
|
frameRect.size.width -= _intercellSpacing.width;
|
|
|
|
// We add some space to separate the cell from the grid
|
|
if (_drawsGrid)
|
|
{
|
|
frameRect.size.width -= 4;
|
|
frameRect.origin.x += 2;
|
|
}
|
|
|
|
// Safety check
|
|
if (frameRect.size.width < 0)
|
|
frameRect.size.width = 0;
|
|
|
|
return frameRect;
|
|
}
|
|
|
|
- (void) setAutoresizesAllColumnsToFit: (BOOL)flag
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (BOOL) autoresizesAllColumnsToFit
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
- (void) sizeLastColumnToFit
|
|
{
|
|
if ((_super_view != nil) && (_numberOfColumns > 0))
|
|
{
|
|
float excess_width;
|
|
float last_column_width;
|
|
NSTableColumn *lastColumn;
|
|
|
|
excess_width = NSMaxX ([self convertRect: [_super_view bounds]
|
|
fromView: _super_view]);
|
|
excess_width -= NSMaxX (_bounds);
|
|
if (excess_width <= 0)
|
|
return;
|
|
lastColumn = [_tableColumns objectAtIndex: (_numberOfColumns - 1)];
|
|
last_column_width = [lastColumn width];
|
|
last_column_width += excess_width;
|
|
[lastColumn setWidth: last_column_width];
|
|
[self tile];
|
|
}
|
|
}
|
|
|
|
- (void) sizeToFit
|
|
{
|
|
NSCell *cell;
|
|
NSEnumerator *enumerator;
|
|
NSTableColumn *tb;
|
|
float table_width;
|
|
float width;
|
|
float candidate_width;
|
|
int row;
|
|
|
|
_tilingDisabled = YES;
|
|
|
|
/* First Step */
|
|
/* Resize Each Column to its Minimum Width */
|
|
table_width = _bounds.origin.x;
|
|
enumerator = [_tableColumns objectEnumerator];
|
|
while ((tb = [enumerator nextObject]) != nil)
|
|
{
|
|
// Compute min width of column
|
|
width = [[tb headerCell] cellSize].width;
|
|
cell = [tb dataCell];
|
|
for (row = 0; row < _numberOfRows; row++)
|
|
{
|
|
[cell setObjectValue: [_dataSource tableView: self
|
|
objectValueForTableColumn: tb
|
|
row: row]];
|
|
if (_del_responds)
|
|
{
|
|
[_delegate tableView: self willDisplayCell: cell
|
|
forTableColumn: tb row: row];
|
|
}
|
|
candidate_width = [cell cellSize].width;
|
|
|
|
if (_drawsGrid)
|
|
candidate_width += 4;
|
|
|
|
if (candidate_width > width)
|
|
{
|
|
width = candidate_width;
|
|
}
|
|
}
|
|
width += _intercellSpacing.width;
|
|
[tb setWidth: width];
|
|
/* It is necessary to ask the column for the width, since it might have
|
|
been changed by the column to constrain it to a min or max width */
|
|
table_width += [tb width];
|
|
}
|
|
|
|
/* Second Step */
|
|
/* If superview (clipview) is bigger than that, divide remaining space
|
|
between all columns */
|
|
if ((_super_view != nil) && (_numberOfColumns > 0))
|
|
{
|
|
float excess_width;
|
|
|
|
excess_width = NSMaxX ([self convertRect: [_super_view bounds]
|
|
fromView: _super_view]);
|
|
excess_width -= table_width;
|
|
if (excess_width <= 0)
|
|
{
|
|
_tilingDisabled = NO;
|
|
[self tile];
|
|
return;
|
|
}
|
|
excess_width = excess_width / _numberOfColumns;
|
|
|
|
enumerator = [_tableColumns objectEnumerator];
|
|
while ((tb = [enumerator nextObject]) != nil)
|
|
{
|
|
[tb setWidth: ([tb width] + excess_width)];
|
|
}
|
|
}
|
|
|
|
_tilingDisabled = NO;
|
|
[self tile];
|
|
}
|
|
|
|
- (void) noteNumberOfRowsChanged
|
|
{
|
|
NSRect superviewBounds; // Get this *after* [self setFrame:]
|
|
|
|
_numberOfRows = [_dataSource numberOfRowsInTableView: self];
|
|
[self setFrame: NSMakeRect (_frame.origin.x,
|
|
_frame.origin.y,
|
|
_frame.size.width,
|
|
(_numberOfRows * _rowHeight) + 1)];
|
|
|
|
/* If we are shorter in height than the enclosing clipview, we
|
|
should redraw us now. */
|
|
superviewBounds = [_super_view bounds];
|
|
if ((superviewBounds.origin.x <= _frame.origin.x)
|
|
&& (NSMaxY (superviewBounds) >= NSMaxY (_frame)))
|
|
{
|
|
[self setNeedsDisplay: YES];
|
|
}
|
|
}
|
|
|
|
- (void) tile
|
|
{
|
|
float table_width = 0;
|
|
float table_height;
|
|
|
|
if (_tilingDisabled == YES)
|
|
return;
|
|
|
|
if (_numberOfColumns > 0)
|
|
{
|
|
int i;
|
|
float width;
|
|
|
|
_columnOrigins[0] = _bounds.origin.x;
|
|
width = [[_tableColumns objectAtIndex: 0] width];
|
|
table_width += width;
|
|
for (i = 1; i < _numberOfColumns; i++)
|
|
{
|
|
_columnOrigins[i] = _columnOrigins[i - 1] + width;
|
|
width = [[_tableColumns objectAtIndex: i] width];
|
|
table_width += width;
|
|
}
|
|
}
|
|
/* + 1 for the last grid line */
|
|
table_height = (_numberOfRows * _rowHeight) + 1;
|
|
[self setFrameSize: NSMakeSize (table_width, table_height)];
|
|
[self setNeedsDisplay: YES];
|
|
|
|
if (_headerView != nil)
|
|
{
|
|
[_headerView setFrameSize:
|
|
NSMakeSize (_frame.size.width,
|
|
[_headerView frame].size.height)];
|
|
[_cornerView setFrameSize:
|
|
NSMakeSize ([NSScroller scrollerWidth] + 1,
|
|
[_headerView frame].size.height)];
|
|
[_headerView setNeedsDisplay: YES];
|
|
[_cornerView setNeedsDisplay: YES];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Drawing
|
|
*/
|
|
|
|
- (void)drawRow: (int)rowIndex clipRect: (NSRect)aRect
|
|
{
|
|
int startingColumn;
|
|
int endingColumn;
|
|
NSTableColumn *tb;
|
|
NSRect drawingRect;
|
|
NSCell *cell;
|
|
int i;
|
|
float x_pos;
|
|
|
|
if (_dataSource == nil)
|
|
return;
|
|
|
|
/* Using columnAtPoint: here would make it called twice per row per drawn rect
|
|
- so we avoid it and do it natively */
|
|
|
|
/* Determine starting column as fast as possible */
|
|
x_pos = NSMinX (aRect);
|
|
i = 0;
|
|
while ((x_pos > _columnOrigins[i]) && (i < _numberOfColumns))
|
|
{
|
|
i++;
|
|
}
|
|
startingColumn = (i - 1);
|
|
|
|
if (startingColumn == -1)
|
|
startingColumn = 0;
|
|
|
|
/* Determine ending column as fast as possible */
|
|
x_pos = NSMaxX (aRect);
|
|
// Nota Bene: we do *not* reset i
|
|
while ((x_pos > _columnOrigins[i]) && (i < _numberOfColumns))
|
|
{
|
|
i++;
|
|
}
|
|
endingColumn = (i - 1);
|
|
|
|
if (endingColumn == -1)
|
|
endingColumn = _numberOfColumns - 1;
|
|
|
|
/* Draw the row between startingColumn and endingColumn */
|
|
for (i = startingColumn; i <= endingColumn; i++)
|
|
{
|
|
tb = [_tableColumns objectAtIndex: i];
|
|
cell = [tb dataCell];
|
|
if (_del_responds)
|
|
{
|
|
[_delegate tableView: self willDisplayCell: cell
|
|
forTableColumn: tb row: rowIndex];
|
|
}
|
|
[cell setObjectValue: [_dataSource tableView: self
|
|
objectValueForTableColumn: tb
|
|
row: rowIndex]];
|
|
drawingRect = [self frameOfCellAtColumn: i
|
|
row: rowIndex];
|
|
[cell drawWithFrame: drawingRect inView: self];
|
|
}
|
|
}
|
|
|
|
- (void) drawGridInClipRect: (NSRect)aRect
|
|
{
|
|
float minX = NSMinX (aRect);
|
|
float maxX = NSMaxX (aRect);
|
|
float minY = NSMinY (aRect);
|
|
float maxY = NSMaxY (aRect);
|
|
/* Using columnAtPoint:, rowAtPoint: here calls them only twice per drawn rect */
|
|
int startingRow = [self rowAtPoint:
|
|
NSMakePoint (_bounds.origin.x, minY)];
|
|
int endingRow = [self rowAtPoint:
|
|
NSMakePoint (_bounds.origin.x, maxY)];
|
|
int startingColumn = [self columnAtPoint:
|
|
NSMakePoint (minX, _bounds.origin.y)];
|
|
int endingColumn = [self columnAtPoint:
|
|
NSMakePoint (maxX, _bounds.origin.y)];
|
|
int i;
|
|
NSGraphicsContext *ctxt = GSCurrentContext ();
|
|
float position;
|
|
|
|
DPSgsave (ctxt);
|
|
DPSsetlinewidth (ctxt, 1);
|
|
[_gridColor set];
|
|
|
|
if (_numberOfRows > 0)
|
|
{
|
|
/* Draw horizontal lines */
|
|
if (startingRow == -1)
|
|
startingRow = 0;
|
|
if (endingRow == -1)
|
|
endingRow = _numberOfRows - 1;
|
|
|
|
position = _bounds.origin.y;
|
|
position += startingRow * _rowHeight;
|
|
for (i = startingRow; i <= endingRow + 1; i++)
|
|
{
|
|
DPSmoveto (ctxt, minX, position);
|
|
DPSlineto (ctxt, maxX, position);
|
|
DPSstroke (ctxt);
|
|
position += _rowHeight;
|
|
}
|
|
}
|
|
|
|
if (_numberOfColumns > 0)
|
|
{
|
|
/* Draw vertical lines */
|
|
if (startingColumn == -1)
|
|
startingColumn = 0;
|
|
if (endingColumn == -1)
|
|
endingColumn = _numberOfColumns - 1;
|
|
|
|
for (i = startingColumn; i <= endingColumn; i++)
|
|
{
|
|
DPSmoveto (ctxt, _columnOrigins[i], minY);
|
|
DPSlineto (ctxt, _columnOrigins[i], maxY);
|
|
DPSstroke (ctxt);
|
|
}
|
|
position = _columnOrigins[endingColumn];
|
|
position += [[_tableColumns objectAtIndex: endingColumn] width];
|
|
/* Last vertical line must moved a pixel to the left */
|
|
if (endingColumn == (_numberOfColumns - 1))
|
|
position -= 1;
|
|
DPSmoveto (ctxt, position, minY);
|
|
DPSlineto (ctxt, position, maxY);
|
|
DPSstroke (ctxt);
|
|
}
|
|
|
|
DPSgrestore (ctxt);
|
|
}
|
|
|
|
- (void) highlightSelectionInClipRect: (NSRect)clipRect
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
- (void) drawRect: (NSRect)aRect
|
|
{
|
|
int startingRow;
|
|
int endingRow;
|
|
int i;
|
|
|
|
/* Draw background */
|
|
[_backgroundColor set];
|
|
NSRectFill (_bounds);
|
|
|
|
if ((_numberOfRows == 0) || (_numberOfColumns == 0))
|
|
return;
|
|
|
|
/* Draw grid */
|
|
if (_drawsGrid)
|
|
{
|
|
[self drawGridInClipRect: aRect];
|
|
}
|
|
|
|
/* Draw visible cells */
|
|
/* Using rowAtPoint: here calls them only twice per drawn rect */
|
|
startingRow = [self rowAtPoint: NSMakePoint (0, NSMinY (aRect))];
|
|
endingRow = [self rowAtPoint: NSMakePoint (0, NSMaxY (aRect))];
|
|
|
|
if (startingRow == -1)
|
|
startingRow = 0;
|
|
if (endingRow == -1)
|
|
endingRow = _numberOfRows - 1;
|
|
|
|
for (i = startingRow; i <= endingRow; i++)
|
|
{
|
|
[self drawRow: i clipRect: aRect];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Scrolling
|
|
*/
|
|
|
|
- (void) scrollRowToVisible: (int)rowIndex
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (void) scrollColumnToVisible: (int)columnIndex
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
|
|
/*
|
|
* Text delegate methods
|
|
*/
|
|
|
|
- (BOOL) textShouldBeginEditing: (NSText *)textObject
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
- (void) textDidBeginEditing: (NSNotification *)aNotification
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (void) textDidChange: (NSNotification *)aNotification
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (BOOL) textShouldEndEditing: (NSText *)textObject
|
|
{
|
|
// TODO
|
|
return YES;
|
|
}
|
|
|
|
- (void) textDidEndEditing: (NSNotification *)aNotification
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Persistence
|
|
*/
|
|
|
|
- (NSString *) autosaveName
|
|
{
|
|
// TODO
|
|
return nil;
|
|
}
|
|
|
|
- (BOOL) autosaveTableColumns
|
|
{
|
|
// TODO
|
|
return NO;
|
|
}
|
|
|
|
- (void) setAutosaveName: (NSString *)name
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
- (void) setAutosaveTableColumns: (BOOL)flag
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
/*
|
|
* Delegate
|
|
*/
|
|
|
|
- (void) setDelegate: (id)anObject
|
|
{
|
|
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
|
SEL sel;
|
|
|
|
if (_delegate)
|
|
[nc removeObserver: _delegate name: nil object: self];
|
|
_delegate = anObject;
|
|
|
|
#define SET_DELEGATE_NOTIFICATION(notif_name) \
|
|
if ([_delegate respondsToSelector: @selector(tableView##notif_name:)]) \
|
|
[nc addObserver: _delegate \
|
|
selector: @selector(tableView##notif_name:) \
|
|
name: NSTableView##notif_name##Notification object: self]
|
|
|
|
SET_DELEGATE_NOTIFICATION(ColumnDidMove);
|
|
SET_DELEGATE_NOTIFICATION(ColumnDidResize);
|
|
SET_DELEGATE_NOTIFICATION(SelectionDidChange);
|
|
SET_DELEGATE_NOTIFICATION(SelectionIsChanging);
|
|
|
|
/* Cache */
|
|
sel = @selector(tableView:willDisplayCell:forTableColumn:row:);
|
|
_del_responds = [_delegate respondsToSelector: sel];
|
|
}
|
|
|
|
- (id) delegate
|
|
{
|
|
return _delegate;
|
|
}
|
|
|
|
/*
|
|
* Encoding/Decoding
|
|
*/
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
{
|
|
[super encodeWithCoder: aCoder];
|
|
// TODO
|
|
}
|
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
|
{
|
|
return [super initWithCoder: aDecoder];
|
|
// TODO
|
|
}
|
|
|
|
@end /* implementation of NSTableView */
|