Live Resizable Date Columns
If you pay attention to little details like I do, you’ll proabably be annoyed by date columns in table and outline views not live resizing. There are some somewhat obvious solutions but they can either be slow or the still don’t have the fluidity you’re looking for. Here’s a pretty simple solution.
The first thing we need is a NSTextFieldCell subclass. In there we’ll override the drawWithFrame:inView: method and determine the format of the date which can fit in the available width of the cell, and then draw the date with that format. Because it’d be really slow to determine the date format for each individual date/row in the column, we’ll use a little trick to do that calculation only once, save the values, and then compare them to know if the column size has changed or not and whether it needs to be recalculated.
@interface AGResizableDateCell : NSTextFieldCell { int mLastWidthDrawnAt; } @end
Whenever mLastWidthDrawnAt is 0 or the current width of the cell does not equal mLastWidthDrawnAt, the format will need to be determined for the current width and mLastWidthDrawnAt will be set to the width.
@implementation AGResizableDateCell - (void)setFormatter:(NSFormatter *)formatter; { if (![formatter isKindOfClass:[NSDateFormatter class]]) { formatter = [[[NSDateFormatter alloc] init] autorelease]; [(NSDateFormatter *)formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [(NSDateFormatter *)formatter setDateStyle:NSDateFormatterLongStyle]; [(NSDateFormatter *)formatter setTimeStyle:NSDateFormatterLongStyle]; } mLastWidthDrawnAt = 0; [super setFormatter:formatter]; }
In the implementation, we always need to make sure the column has a date formatter. I’m using the 10.4 date formatter behavior because, well, it works better and Araelium Edit requires 10.4 anyway, so I can.
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView; { NSDate * date = [NSDate dateWithNaturalLanguageString:@"February 22, 2006 12:55 PM"]; NSDateFormatter * formatter = [self formatter]; NSDictionary * attribs = [NSDictionary dictionaryWithObjectsAndKeys: [(NSTableView *)controlView font], NSFontAttributeName, nil]; if (!formatter) { [self setFormatter:nil]; formatter = [self formatter]; } if (mLastWidthDrawnAt != (int)cellFrame.size.width) { [formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [formatter setDateStyle:NSDateFormatterLongStyle]; [formatter setTimeStyle:NSDateFormatterLongStyle]; mLastWidthDrawnAt = (int)cellFrame.size.width;
When drawing, it first makes sure there’s a formatter, and then will check to see if the cell size has changed since the last time it was used to draw. Because the format is calculated once, and not for each individual row, you need to start out with a date that’s as wide as possible. For this reason, the date being used (February 22, 2006 12:55 PM) is the widest date for each of its components. I admit this a bit ugly, but honestly I couldn’t think of a better solution and it works well anyway (for my needs).
while (YES) { NSString * string = [formatter stringForObjectValue:date]; NSSize size = [string sizeWithAttributes:attribs]; size.width += 8.0; // Add some padding! if (size.width > cellFrame.size.width) { if ([formatter dateStyle] == NSDateFormatterShortStyle && [formatter timeStyle] == NSDateFormatterNoStyle) { break; } if ([formatter timeStyle] >= [formatter dateStyle]) { [formatter setTimeStyle:[formatter timeStyle] - 1]; } else if ([formatter dateStyle] > [formatter timeStyle]) { [formatter setDateStyle:[formatter dateStyle] - 1]; } } else { break; } } }
This part is a bit long, but it’s conceptually simple. Starting with the longest date format, we test the width of the resulting string against the width of the cell. If it’s too wide, we shrink the format for the time. If it is still too wide, we shrink the format for the date. If it’s still too wide, we shrink the format for the time again, etc until it fits.
cellFrame.size.height -= 2.0; cellFrame.origin.y += 1.0; [super drawWithFrame:cellFrame inView:controlView]; }
And lastly, the date is actually drawn.
The project:
Project







Comments(0)