News Software Download Buy Now About Us Developers Contact
software TOC | PREV | NEXT
SDTableView: allow drag reordering

GIFfun lets you click on the image and drag it to a new location in the animation. There are better ways to do this, I just wanted a way that was quick and easy and didn't require diving too far down into the NSTableView. First, we define a Protocol for reordering delegates:

@protocol SDMovingRowsProtocol

// Which key modifiers enable reordering? OR them together
// exp: return (NSCommandKeyMask|NSAlternateKeyMask);
// if you want the default behaviour to alas drag cells
// pass this pack for

#define DRAG_ALWAYS    0
- (unsigned int)dragReorderingMask:(int)forColumn;

// After the reordering of cells - you must reorder your data.
// Returning YES will cause the table to be reloaded.

- (BOOL)tableView:(NSTableView *)tv didDepositRow:(int)rowToMove at:(int)newPosition;

- (NSImage *)imageForRow:(int)row;
- (void)willMoveRow:(int)row;


In SDTableView, we override mouseDown: to see if the delegate understands this protocol and whether it wants to reorder:

- (void)mouseDown:(NSEvent *)e
if (![self move:e]) [super mouseDown:e];

- (BOOL)move:(NSEvent *)e
unsigned int flags = [e modifierFlags];
NSPoint mouseDownLocation = [e locationInWindow];
int col;

mouseDownLocation = [self convertPoint:mouseDownLocation fromView:nil];
col = [self columnAtPoint:mouseDownLocation];

if ([[self delegate] conformsToProtocol:@protocol(SDMovingRowsProtocol)] &&
((flags & [[self delegate]dragReorderingMask:col]) ||
([[self delegate]dragReorderingMask:col] == DRAG_ALWAYS))) {
int endRow, hitRow;

hitRow = [self rowAtPoint:mouseDownLocation];
[[self delegate] willMoveRow:hitRow];
[[self moveCursor] push];
[super mouseDown:e];
[[self moveCursor] pop];

mouseDownLocation = [[[self window] currentEvent] locationInWindow];
mouseDownLocation = [self convertPoint:mouseDownLocation fromView:nil];
endRow = [self rowAtPoint:mouseDownLocation];

return [self startRow:hitRow endedAt:endRow];

return NO;

// We send the information to our delegate when done moving:

- (BOOL)startRow:(int)start endedAt:(int)end
if (end != -1 && start != -1 && end != start &&
    [[self delegate] tableView:self didDepositRow:start at:end]) {
[self reloadData];
[self selectRow:end byExtendingSelection:NO];
    return YES;
return NO;

Created by Stone Design's Create on 4/30/1998
©2000 Stone Design top