API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
CPTableHeaderView.j
Go to the documentation of this file.
1 /*
2  * CPTableHeaderView.j
3  * AppKit
4  *
5  * Created by Ross Boucher.
6  * Copyright 2009 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 
26 @implementation _CPTableColumnHeaderView : CPView
27 {
28  _CPImageAndTextView _textField;
29 }
30 
31 + (CPString)defaultThemeClass
32 {
33  return @"columnHeader";
34 }
35 
36 + (id)themeAttributes
37 {
38  return [CPDictionary dictionaryWithObjects:[[CPNull null], CPLeftTextAlignment, CPLineBreakByTruncatingTail, CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()]
39  forKeys:[@"background-color", @"text-alignment", @"line-break-mode", @"text-inset", @"text-color", @"font", @"text-shadow-color", @"text-shadow-offset"]];
40 }
41 
42 - (void)initWithFrame:(CGRect)frame
43 {
44  self = [super initWithFrame:frame];
45  if (self)
46  [self _init];
47 
48  return self;
49 }
50 
51 - (void)_init
52 {
53  _textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
54 
55  [_textField setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
56 
57  [_textField setLineBreakMode:CPLineBreakByTruncatingTail];
58  [_textField setAlignment:CPLeftTextAlignment];
59  [_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
60 
61  [self addSubview:_textField];
62 }
63 
64 - (void)layoutSubviews
65 {
66  [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
67 
68  var inset = [self currentValueForThemeAttribute:@"text-inset"],
69  bounds = [self bounds];
70 
71  [_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
72  [_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
73  [_textField setFont:[self currentValueForThemeAttribute:@"font"]];
74  [_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
75  [_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
76  [_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
77  [_textField setLineBreakMode:[self currentValueForThemeAttribute:@"line-break-mode"]];
78 }
79 
80 - (void)setStringValue:(CPString)string
81 {
82  [_textField setText:string];
83 }
84 
85 - (CPString)stringValue
86 {
87  return [_textField text];
88 }
89 
90 - (void)textField
91 {
92  return _textField;
93 }
94 
95 - (void)sizeToFit
96 {
97  [_textField sizeToFit];
98 }
99 
100 - (void)setFont:(CPFont)aFont
101 {
102  [self setValue:aFont forThemeAttribute:@"font"];
103 }
104 
105 - (CPFont)font
106 {
107  return [self currentValueForThemeAttribute:@"font"]
108 }
109 
110 - (void)setAlignment:(CPTextAlignment)alignment
111 {
112  [self setValue:alignment forThemeAttribute:@"text-alignment"];
113 }
114 
115 - (CPTextAlignment)alignment
116 {
117  return [self currentValueForThemeAttribute:@"text-alignment"]
118 }
119 
120 - (void)setLineBreakMode:(CPLineBreakMode)mode
121 {
122  [self setValue:mode forThemeAttribute:@"line-break-mode"];
123 }
124 
125 - (CPLineBreakMode)lineBreakMode
126 {
127  return [self currentValueForThemeAttribute:@"line-break-mode"]
128 }
129 
130 - (void)setTextColor:(CPColor)aColor
131 {
132  [self setValue:aColor forThemeAttribute:@"text-color"];
133 }
134 
135 - (CPColor)textColor
136 {
137  return [self currentValueForThemeAttribute:@"text-color"]
138 }
139 
140 - (void)setTextShadowColor:(CPColor)aColor
141 {
142  [self setValue:aColor forThemeAttribute:@"text-shadow-color"];
143 }
144 
145 - (CPColor)textShadowColor
146 {
147  return [self currentValueForThemeAttribute:@"text-shadow-color"]
148 }
149 
150 - (void)_setIndicatorImage:(CPImage)anImage
151 {
152  if (anImage)
153  {
154  [_textField setImage:anImage];
155  [_textField setImagePosition:CPImageRight];
156  }
157  else
158  {
159  [_textField setImagePosition:CPNoImage];
160  }
161 }
162 
163 @end
164 
165 var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringValueKey",
166  _CPTableColumnHeaderViewFontKey = @"_CPTableColumnHeaderViewFontKey",
167  _CPTableColumnHeaderViewTextColorKey = @"_CPTableColumnHeaderViewTextColorKey",
168  _CPTableColumnHeaderViewTextShadowColorKey = @"_CPTableColumnHeaderViewTextShadowColorKey",
169  _CPTableColumnHeaderViewAlignmentKey = @"_CPTableColumnHeaderViewAlignmentKey",
170  _CPTableColumnHeaderViewLineBreakModeKey = @"_CPTableColumnHeaderViewLineBreakModeKey",
171  _CPTableColumnHeaderViewImageKey = @"_CPTableColumnHeaderViewImageKey";
172 
173 @implementation _CPTableColumnHeaderView (CPCoding)
174 
175 - (id)initWithCoder:(CPCoder)aCoder
176 {
177  if (self = [super initWithCoder:aCoder])
178  {
179  [self _init];
180  [self _setIndicatorImage:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewImageKey]];
181  [self setStringValue:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewStringValueKey]];
182  [self setFont:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewFontKey]];
183  [self setTextColor:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewTextColorKey]];
184  [self setTextShadowColor:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewTextShadowColorKey]];
185  [self setAlignment:[aCoder decodeIntForKey:_CPTableColumnHeaderViewAlignmentKey]];
186  [self setLineBreakMode:[aCoder decodeIntForKey:_CPTableColumnHeaderViewLineBreakModeKey]];
187  }
188 
189  return self;
190 }
191 
192 - (void)encodeWithCoder:(CPCoder)aCoder
193 {
194  [super encodeWithCoder:aCoder];
195 
196  [aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
197  [aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
198  [aCoder encodeObject:[self font] forKey:_CPTableColumnHeaderViewFontKey];
199  [aCoder encodeObject:[self textColor] forKey:_CPTableColumnHeaderViewTextColorKey];
200  [aCoder encodeObject:[self textShadowColor] forKey:_CPTableColumnHeaderViewTextShadowColorKey];
201  [aCoder encodeInt:[self alignment] forKey:_CPTableColumnHeaderViewAlignmentKey];
202  [aCoder encodeInt:[self lineBreakMode] forKey:_CPTableColumnHeaderViewLineBreakModeKey];
203 }
204 
205 @end
206 
207 @implementation CPTableHeaderView : CPView
208 {
209  CGPoint _mouseDownLocation;
210  CGPoint _previousTrackingLocation;
211  int _activeColumn;
212  int _pressedColumn;
213 
214  BOOL _isResizing;
215  BOOL _isDragging;
216  BOOL _isTrackingColumn;
217  BOOL _drawsColumnLines;
218 
219  float _columnOldWidth;
220 
221  CPTableView _tableView;
222 }
223 
224 + (CPString)defaultThemeClass
225 {
226  return @"tableHeaderRow";
227 }
228 
229 + (id)themeAttributes
230 {
232  forKeys:[@"background-color", @"divider-color"]];
233 }
234 
235 - (void)_init
236 {
237  _mouseDownLocation = _CGPointMakeZero();
238  _previousTrackingLocation = _CGPointMakeZero();
239  _activeColumn = -1;
240  _pressedColumn = -1;
241 
242  _isResizing = NO;
243  _isDragging = NO;
244  _isTrackingColumn = NO;
245  _drawsColumnLines = YES;
246 
247  _columnOldWidth = 0.0;
248 
249  [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
250 }
251 
252 - (id)initWithFrame:(CGRect)aFrame
253 {
254  self = [super initWithFrame:aFrame];
255 
256  if (self)
257  [self _init];
258 
259  return self;
260 }
261 
262 - (int)columnAtPoint:(CGPoint)aPoint
263 {
264  return [_tableView columnAtPoint:CGPointMake(aPoint.x, aPoint.y)];
265 }
266 
267 - (CGRect)headerRectOfColumn:(int)aColumnIndex
268 {
269  var headerRect = CGRectMakeCopy([self bounds]),
270  columnRect = [_tableView rectOfColumn:aColumnIndex];
271 
272  headerRect.origin.x = _CGRectGetMinX(columnRect);
273  headerRect.size.width = _CGRectGetWidth(columnRect);
274 
275  return headerRect;
276 }
277 
278 - (void)setDrawsColumnLines:(BOOL)aFlag
279 {
280  _drawsColumnLines = aFlag;
281 }
282 
283 - (BOOL)drawsColumnLines
284 {
285  return _drawsColumnLines;
286 }
287 
288 - (CGRect)_cursorRectForColumn:(int)column
289 {
290  if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
291  return _CGRectMakeZero();
292 
293  var rect = [self headerRectOfColumn:column];
294 
295  rect.origin.x = _CGRectGetMaxX(rect) - 5;
296  rect.size.width = 20;
297 
298  return rect;
299 }
300 
301 - (void)_setPressedColumn:(CPInteger)column
302 {
303  if (_pressedColumn != -1)
304  {
305  var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
306  [headerView unsetThemeState:CPThemeStateHighlighted];
307  }
308 
309  if (column != -1)
310  {
311  var headerView = [_tableView._tableColumns[column] headerView];
312  [headerView setThemeState:CPThemeStateHighlighted];
313  }
314 
315  _pressedColumn = column;
316 }
317 
318 - (void)mouseDown:(CPEvent)theEvent
319 {
320  [self trackMouse:theEvent];
321 }
322 
323 - (void)trackMouse:(CPEvent)theEvent
324 {
325  var type = [theEvent type],
326  currentLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil];
327 
328  // Take the right columns resize tracking area into account
329  currentLocation.x -= 5.0;
330 
331  var columnIndex = [self columnAtPoint:currentLocation],
332  shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
333 
334  if (type === CPLeftMouseUp)
335  {
336  if (shouldResize)
337  [self stopResizingTableColumn:_activeColumn at:currentLocation];
338  else if ([self _shouldStopTrackingTableColumn:columnIndex at:currentLocation])
339  {
340  [_tableView _didClickTableColumn:columnIndex modifierFlags:[theEvent modifierFlags]];
341  [self stopTrackingTableColumn:columnIndex at:currentLocation];
342 
343  _isTrackingColumn = NO;
344  }
345 
346  [self _updateResizeCursor:[CPApp currentEvent]];
347 
348  _activeColumn = CPNotFound;
349  return;
350  }
351 
352  if (type === CPLeftMouseDown)
353  {
354  if (columnIndex === -1)
355  return;
356 
357  _mouseDownLocation = currentLocation;
358  _activeColumn = columnIndex;
359 
360  [_tableView _sendDelegateDidMouseDownInHeader:columnIndex];
361 
362  if (shouldResize)
363  [self startResizingTableColumn:columnIndex at:currentLocation];
364  else
365  {
366  [self startTrackingTableColumn:columnIndex at:currentLocation];
367  _isTrackingColumn = YES;
368  }
369  }
370  else if (type === CPLeftMouseDragged)
371  {
372  if (shouldResize)
373  [self continueResizingTableColumn:_activeColumn at:currentLocation];
374  else
375  {
376  if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
377  {
378  if (_isTrackingColumn && _pressedColumn !== -1)
379  {
380  if (![self continueTrackingTableColumn:columnIndex at:currentLocation])
381  return; // Stop tracking the column, because it's being dragged
382  } else
383  [self startTrackingTableColumn:columnIndex at:currentLocation];
384 
385  } else if (_isTrackingColumn && _pressedColumn !== -1)
386  [self stopTrackingTableColumn:_activeColumn at:currentLocation];
387  }
388  }
389 
390  _previousTrackingLocation = currentLocation;
391  [CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
392 }
393 
394 - (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
395 {
396  [self _setPressedColumn:aColumnIndex];
397 }
398 
399 - (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
400 {
401  if ([self _shouldDragTableColumn:aColumnIndex at:aPoint])
402  {
403  var columnRect = [self headerRectOfColumn:aColumnIndex],
404  offset = _CGPointMakeZero(),
405  view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset],
406  viewLocation = _CGPointMakeZero();
407 
408  viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
409  viewLocation.y = _CGRectGetMinY(columnRect) + offset.y;
410 
411  [self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent]
412  pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES];
413 
414  return NO;
415  }
416 
417  return YES;
418 }
419 
420 - (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
421 {
422  return _isTrackingColumn && _activeColumn === aColumnIndex &&
423  _CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
424 }
425 
426 - (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
427 {
428  [self _setPressedColumn:CPNotFound];
429  [self _updateResizeCursor:[CPApp currentEvent]];
430 }
431 
432 - (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
433 {
434  return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
435 }
436 
437 - (CGRect)_headerRectOfLastVisibleColumn
438 {
439  var tableColumns = [_tableView tableColumns],
440  columnIndex = [tableColumns count];
441 
442  while (columnIndex--)
443  {
444  var tableColumn = [tableColumns objectAtIndex:columnIndex];
445 
446  if (![tableColumn isHidden])
447  return [self headerRectOfColumn:columnIndex];
448  }
449 
450  return nil;
451 }
452 
453 - (void)_constrainDragView:(CPView)theDragView at:(CGPoint)aPoint
454 {
455  var tableColumns = [_tableView tableColumns],
456  lastColumnRect = [self _headerRectOfLastVisibleColumn],
457  activeColumnRect = [self headerRectOfColumn:_activeColumn],
458  dragWindow = [theDragView window],
459  frame = [dragWindow frame];
460 
461  // Convert the frame origin from the global coordinate system to the windows' coordinate system
462  frame.origin = [[self window] convertGlobalToBase:frame.origin];
463  // the from the window to the view
464  frame.origin = [self convertPoint:frame.origin fromView:nil];
465 
466  // This effectively clamps the value between the minimum and maximum
467  frame.origin.x = MAX(0.0, MIN(_CGRectGetMinX(frame), _CGRectGetMaxX(lastColumnRect) - _CGRectGetWidth(activeColumnRect)));
468 
469  // Make sure the column cannot move vertically
470  frame.origin.y = _CGRectGetMinY(lastColumnRect);
471 
472  // Convert the calculated origin back to the window coordinate system
473  frame.origin = [self convertPoint:frame.origin toView:nil];
474  // Then back to the global coordinate system
475  frame.origin = [[self window] convertBaseToGlobal:frame.origin];
476 
477  [dragWindow setFrame:frame];
478 }
479 
480 - (void)_moveColumn:(int)aFromIndex toColumn:(int)aToIndex
481 {
482  [_tableView moveColumn:aFromIndex toColumn:aToIndex];
483  _activeColumn = aToIndex;
484  _pressedColumn = _activeColumn;
485 }
486 
487 - (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
488 {
489  _isDragging = YES;
490 
491  var column = [[_tableView tableColumns] objectAtIndex:_activeColumn];
492 
493  [[column headerView] setHidden:YES];
494  [_tableView _setDraggedColumn:column];
495 
496  [self setNeedsDisplay:YES];
497 }
498 
499 - (void)draggedView:(CPView)aView movedTo:(CGPoint)aPoint
500 {
501  [self _constrainDragView:aView at:aPoint];
502 
503  var dragWindow = [aView window],
504  dragWindowFrame = [dragWindow frame];
505 
506  var hoverPoint = CGPointCreateCopy(aPoint);
507 
508  if (aPoint.x < _previousTrackingLocation.x)
509  hoverPoint = _CGPointMake(_CGRectGetMinX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
510  else if (aPoint.x > _previousTrackingLocation.x)
511  hoverPoint = _CGPointMake(_CGRectGetMaxX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
512 
513  // Convert the hover point from the global coordinate system to windows' coordinate system
514  hoverPoint = [[self window] convertGlobalToBase:hoverPoint];
515  // then to the view
516  hoverPoint = [self convertPoint:hoverPoint fromView:nil];
517 
518  var hoveredColumn = [self columnAtPoint:hoverPoint];
519 
520  if (hoveredColumn !== -1)
521  {
522  var columnRect = [self headerRectOfColumn:hoveredColumn],
523  columnCenterPoint = [self convertPoint:CGPointMake(_CGRectGetMidX(columnRect), _CGRectGetMidY(columnRect)) fromView:self];
524  if (hoveredColumn < _activeColumn && hoverPoint.x < columnCenterPoint.x)
525  [self _moveColumn:_activeColumn toColumn:hoveredColumn];
526  else if (hoveredColumn > _activeColumn && hoverPoint.x > columnCenterPoint.x)
527  [self _moveColumn:_activeColumn toColumn:hoveredColumn];
528  }
529 
530  _previousTrackingLocation = aPoint;
531 }
532 
533 - (void)draggedView:(CPImage)aView endedAt:(CGPoint)aLocation operation:(CPDragOperation)anOperation
534 {
535  _isDragging = NO;
536  _isTrackingColumn = NO; // We need to do this explicitly because the mouse up section of trackMouse is never reached
537 
538  [_tableView _setDraggedColumn:nil];
539  [[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO];
540  [self stopTrackingTableColumn:_activeColumn at:aLocation];
541 
542  [self setNeedsDisplay:YES];
543 }
544 
545 - (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
546 {
547  if (_isResizing)
548  return YES;
549 
550  if (_isTrackingColumn)
551  return NO;
552 
553  return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
554 }
555 
556 - (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
557 {
558  _isResizing = YES;
559 
560  var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
561 
562  [tableColumn setDisableResizingPosting:YES];
563  [_tableView setDisableAutomaticResizing:YES];
564 }
565 
566 - (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
567 {
568  var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
569  newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x;
570 
571  if (newWidth < [tableColumn minWidth])
573  else if (newWidth > [tableColumn maxWidth])
575  else
576  {
577  _tableView._lastColumnShouldSnap = NO;
578  [tableColumn setWidth:newWidth];
579 
581  [self setNeedsLayout];
582  [self setNeedsDisplay:YES];
583  }
584 }
585 
586 - (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
587 {
588  var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
589  [tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
590  [tableColumn setDisableResizingPosting:NO];
591  [_tableView setDisableAutomaticResizing:NO];
592 
593  _isResizing = NO;
594 }
595 
596 - (void)_updateResizeCursor:(CPEvent)theEvent
597 {
598  // never get stuck in resize cursor mode (FIXME take out when we turn on tracking rects)
599  if (![_tableView allowsColumnResizing] || ([theEvent type] === CPLeftMouseUp && ![[self window] acceptsMouseMovedEvents]))
600  {
602  return;
603  }
604 
605  var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
606  mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
607  overColumn = [self columnAtPoint:mouseOverLocation];
608 
609  if (overColumn >= 0 && _CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
610  {
611  var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
612  width = [tableColumn width];
613 
614  if (width == [tableColumn minWidth])
616  else if (width == [tableColumn maxWidth])
618  else
620  }
621  else
623 }
624 
625 - (void)mouseEntered:(CPEvent)theEvent
626 {
627  [self _updateResizeCursor:theEvent];
628 }
629 
630 - (void)mouseMoved:(CPEvent)theEvent
631 {
632  [self _updateResizeCursor:theEvent];
633 }
634 
635 - (void)mouseExited:(CPEvent)theEvent
636 {
637  // FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
639 }
640 
641 - (void)layoutSubviews
642 {
643  var tableColumns = [_tableView tableColumns],
644  count = [tableColumns count];
645 
646  for (var i = 0; i < count; i++)
647  {
648  var column = [tableColumns objectAtIndex:i],
649  headerView = [column headerView],
650  frame = [self headerRectOfColumn:i];
651 
652  // Make space for the gridline on the right.
653  frame.origin.x -= 0.5;
654  frame.size.width -= 1.0;
655  frame.size.height -= 0.5;
656  // Note: we're not adding in intercell spacing here. This setting only affects the regular
657  // table cell data views, not the header. Verified in Cocoa on March 29th, 2011.
658 
659  [headerView setFrame:frame];
660 
661  if ([headerView superview] != self)
662  [self addSubview:headerView];
663  }
664 
665  [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
666 }
667 
668 - (void)drawRect:(CGRect)aRect
669 {
670  if (!_tableView || ![self drawsColumnLines])
671  return;
672 
674  exposedColumnIndexes = [_tableView columnIndexesInRect:aRect],
675  columnsArray = [],
676  tableColumns = [_tableView tableColumns],
677  exposedTableColumns = _tableView._exposedColumns,
678  firstIndex = [exposedTableColumns firstIndex],
679  exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
680 
681  CGContextSetLineWidth(context, 1);
682  CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
683 
684  [exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
685 
686  var columnArrayIndex = 0,
687  columnArrayCount = columnsArray.length,
688  columnMaxX;
689 
690  CGContextBeginPath(context);
691  for (; columnArrayIndex < columnArrayCount; columnArrayIndex++)
692  {
693  // grab each column rect and add vertical lines
694  var columnIndex = columnsArray[columnArrayIndex],
695  columnToStroke = [self headerRectOfColumn:columnIndex];
696 
697  columnMaxX = _CGRectGetMaxX(columnToStroke);
698 
699  CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
700  CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMaxY(columnToStroke)) - 1.0);
701  }
702  CGContextClosePath(context);
703  CGContextStrokePath(context);
704 
705  /*if (_isDragging)
706  {
707  CGContextSetFillColor(context, [CPColor grayColor]);
708  CGContextFillRect(context, [self headerRectOfColumn:_activeColumn])
709  }*/
710 }
711 
712 @end
713 
714 var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
715  CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
716 
718 
719 - (id)initWithCoder:(CPCoder)aCoder
720 {
721  if (self = [super initWithCoder:aCoder])
722  {
723  [self _init];
724  _tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
725 
726  // FIX ME: Take this out before 1.0
727  if ([aCoder containsValueForKey:CPTableHeaderViewDrawsColumnLines])
728  _drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
729  else
730  {
731  _drawsColumnLines = YES;
732  CPLog.warn("The tableview header being decoded is using an old cib. Please run Nib2Cib.");
733  }
734  }
735 
736  return self;
737 }
738 
739 - (void)encodeWithCoder:(CPCoder)aCoder
740 {
741  [super encodeWithCoder:aCoder];
742  [aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
743  [aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
744 }
745 
746 @end
747 
749 
754 {
755  return _tableView;
756 }
757 
761 - (void)setTableView:(CPTableView)aValue
762 {
763  _tableView = aValue;
764 }
765 
766 @end