diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index f276ebd74..7e5b948f1 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -40,6 +40,10 @@ CPApp = nil; CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification"; CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification"; CPApplicationWillTerminateNotification = @"CPApplicationWillTerminateNotification"; +CPApplicationWillBecomeActiveNotification = @"CPApplicationWillBecomeActiveNotification"; +CPApplicationDidBecomeActiveNotification = @"CPApplicationDidBecomeActiveNotification"; +CPApplicationWillResignActiveNotification = @"CPApplicationWillResignActiveNotification"; +CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification"; CPTerminateNow = YES; CPTerminateCancel = NO; @@ -83,6 +87,8 @@ CPRunContinuesResponse = -1002; CPArray _windows; CPWindow _keyWindow; CPWindow _mainWindow; + CPWindow _previousKeyWindow; + CPWindow _previousMainWindow; CPMenu _mainMenu; CPDocumentController _documentController; @@ -92,6 +98,7 @@ CPRunContinuesResponse = -1002; // id _delegate; BOOL _finishedLaunching; + BOOL _isActive; CPDictionary _namedArgs; CPArray _args; @@ -219,6 +226,26 @@ CPRunContinuesResponse = -1002; removeObserver:_delegate name:CPApplicationDidFinishLaunchingNotification object:self]; + + [defaultCenter + removeObserver:_delegate + name:CPApplicationWillBecomeActiveNotification + object:self]; + + [defaultCenter + removeObserver:_delegate + name:CPApplicationDidBecomeActiveNotification + object:self]; + + [defaultCenter + removeObserver:_delegate + name:CPApplicationWillResignActiveNotification + object:self]; + + [defaultCenter + removeObserver:_delegate + name:CPApplicationDidResignActiveNotification + object:self]; } _delegate = aDelegate; @@ -236,6 +263,34 @@ CPRunContinuesResponse = -1002; selector:@selector(applicationDidFinishLaunching:) name:CPApplicationDidFinishLaunchingNotification object:self]; + + if ([_delegate respondsToSelector:@selector(applicationWillBecomeActive:)]) + [defaultCenter + addObserver:_delegate + selector:@selector(applicationWillBecomeActive:) + name:CPApplicationWillBecomeActiveNotification + object:self]; + + if ([_delegate respondsToSelector:@selector(applicationDidBecomeActive:)]) + [defaultCenter + addObserver:_delegate + selector:@selector(applicationDidBecomeActive:) + name:CPApplicationDidBecomeActiveNotification + object:self]; + + if ([_delegate respondsToSelector:@selector(applicationWillResignActive:)]) + [defaultCenter + addObserver:_delegate + selector:@selector(applicationWillResignActive:) + name:CPApplicationWillResignActiveNotification + object:self]; + + if ([_delegate respondsToSelector:@selector(applicationDidResignActive:)]) + [defaultCenter + addObserver:_delegate + selector:@selector(applicationDidResignActive:) + name:CPApplicationDidResignActiveNotification + object:self]; } /*! @@ -419,7 +474,27 @@ CPRunContinuesResponse = -1002; - (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps { + [self _willBecomeActive]; + [CPPlatform activateIgnoringOtherApps:shouldIgnoreOtherApps]; + _isActive = YES; + + [self _willResignActive]; +} + +- (void)deactivate +{ + [self _willResignActive]; + + [CPPlatform deactivate]; + _isActive = NO; + + [self _didResignActive]; +} + +- (void)isActive +{ + return _isActive; } - (void)hideOtherApplications:(id)aSender @@ -624,6 +699,14 @@ CPRunContinuesResponse = -1002; return _windows; } +/*! + Returns an array of visible CPWindow objects, ordered by their front to back order on the screen. +*/ +- (CPArray)orderedWindows +{ + return CPWindowObjectList(); +} + - (void)hide:(id)aSender { [CPPlatform hide:self]; @@ -953,10 +1036,65 @@ CPRunContinuesResponse = -1002; return !![_documentController openDocumentWithContentsOfURL:aURL display:YES error:NULL]; } +- (void)_willBecomeActive +{ + [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification + object:self + userInfo:nil]; +} + +- (void)_didBecomeActive +{ + if (![self keyWindow] && _previousKeyWindow && + [[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound) + [_previousKeyWindow makeKeyWindow]; + + if (![self mainWindow] && _previousMainWindow && + [[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound) + [_previousMainWindow makeMainWindow]; + + if ([self keyWindow]) + [[self keyWindow] orderFront:self]; + else if ([self mainWindow]) + [[self mainWindow] makeKeyAndOrderFront:self]; + else + [[[self mainMenu] window] makeKeyWindow]; //FIXME this may not actually work + + _previousKeyWindow = nil; + _previousMainWindow = nil; + + [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification + object:self + userInfo:nil]; +} + +- (void)_willResignActive +{ + [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification + object:self + userInfo:nil]; +} + - (void)_didResignActive { if (self._activeMenu) [self._activeMenu cancelTracking]; + + if ([self keyWindow]) + { + _previousKeyWindow = [self keyWindow]; + [_previousKeyWindow resignKeyWindow]; + } + + if ([self mainWindow]) + { + _previousMainWindow = [self mainWindow]; + [_previousMainWindow resignMainWindow]; + } + + [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification + object:self + userInfo:nil]; } + (CPString)defaultThemeName diff --git a/AppKit/CPCursor.j b/AppKit/CPCursor.j index f5e67f692..95b1dc79a 100755 --- a/AppKit/CPCursor.j +++ b/AppKit/CPCursor.j @@ -230,8 +230,6 @@ var currentCursor = nil, + (void)_setCursorCSS:(CPString)aString { #if PLATFORM(DOM) - [CPPlatformWindow primaryPlatformWindow]._DOMBodyElement.style.cursor = aString; - var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects]; for (var i = 0, count = [platformWindows count]; i < count; i++) platformWindows[i]._DOMBodyElement.style.cursor = aString; diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j index 4ac925530..48a2dd8f3 100644 --- a/AppKit/CPOutlineView.j +++ b/AppKit/CPOutlineView.j @@ -50,6 +50,14 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10; + +var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1, + CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 2; + CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 3, + CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 4; + +CPOutlineViewDropOnItemIndex = -1; + @implementation CPOutlineView : CPTableView { id _outlineViewDataSource; @@ -60,6 +68,7 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ BOOL _indentationMarkerFollowsDataView; CPInteger _implementedOutlineViewDataSourceMethods; + CPInteger _implementedOutlineViewDelegateMethods; Object _rootItemInfo; CPMutableArray _itemsForRows; @@ -69,6 +78,12 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ CPArray _disclosureControlsForRows; CPData _disclosureControlData; CPArray _disclosureControlQueue; + + BOOL _shouldRetargetItem; + id _retargetedItem; + + BOOL _shouldRetargetChildIndex; + CPInteger _retargedChildIndex; } - (id)initWithFrame:(CGRect)aFrame @@ -87,10 +102,17 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ _itemInfosForItems = { }; _disclosureControlsForRows = []; + _retargetedItem = nil; + _shouldRetargetItem = NO; + + _retargedChildIndex = nil; + _shouldRetargetChildIndex = NO; + [self setIndentationPerLevel:16.0]; [self setIndentationMarkerFollowsDataView:YES]; [super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]]; + [super setDelegate:[[_CPOutlineViewTableViewDelegate alloc] initWithOutlineView:self]]; [self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]]; } @@ -184,20 +206,32 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ - (void)expandItem:(id)anItem { - if (!anItem) - return; + [self expandItem:anItem expandChildren:NO]; +} - var itemInfo = _itemInfosForItems[[anItem UID]]; +- (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren +{ + var itemInfo = null; + + if (!anItem) + itemInfo = _rootItemInfo; + else + itemInfo = _itemInfosForItems[[anItem UID]]; if (!itemInfo) return; - - if (itemInfo.isExpanded) - return; - + itemInfo.isExpanded = YES; - [self reloadItem:anItem reloadChildren:YES]; + + if (shouldExpandChildren) + { + var children = itemInfo.children, + childIndex = children.length; + + while (childIndex--) + [self expandItem:children[childIndex] expandChildren:YES]; + } } - (void)collapseItem:(id)anItem @@ -327,7 +361,13 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ if (!itemInfo) return nil; - return itemInfo.parent; + var parent = itemInfo.parent; + + // Check if the parent is the root item because we never return the actual root item + if (itemInfo[[parent UID]] === _rootItemInfo) + parent = nil; + + return parent; } - (CGRect)frameOfOutlineDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow @@ -341,6 +381,45 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ return frame; } +- (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection +{ + // First un highlight the old disclosure controls + var previousSelectedRows = []; + [[self selectedRowIndexes] getIndexes:previousSelectedRows maxCount:-1 inIndexRange:nil]; + + var index = [previousSelectedRows count]; + while (index--) + { + var rowIndex = previousSelectedRows[index], + item = [self itemAtRow:rowIndex]; + + if (![self isExpandable:item]) + continue; + + var control = _disclosureControlsForRows[rowIndex]; + [control setHighlighted:NO]; + } + + [super selectRowIndexes:rows byExtendingSelection:shouldExtendSelection]; + + // Now highlight the new disclosure controls + var selectedRows = []; + [rows getIndexes:selectedRows maxCount:-1 inIndexRange:nil]; + + var index = [selectedRows count]; + while (index--) + { + var rowIndex = selectedRows[index], + item = [self itemAtRow:rowIndex]; + + if (![self isExpandable:item]) + continue; + + var control = _disclosureControlsForRows[rowIndex]; + [control setHighlighted:YES]; + } +} + - (void)setDelegate:(id)aDelegate { if (_outlineViewDelegate === aDelegate) @@ -375,63 +454,21 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ object:self]; } - _outlineViewDelegate = aDelegate;/* - _implementedDelegateMethods = 0; + _outlineViewDelegate = aDelegate; + _implementedOutlineViewDelegateMethods = 0; - if ([_outlineViewDelegate respondsToSelector:@selector(selectionShouldChangeInTableView:)]) - _implementedDelegateMethods |= CPTableViewDelegate_selectionShouldChangeInTableView_; + if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:dataViewForTableColumn:item:)]) + _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_; + + if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:shouldSelectItem:)]) + _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_shouldSelectItem_; + + if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:heightOfRowByItem:)]) + _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_heightOfRowByItem_; - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:dataViewForTableColumn:row:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_dataViewForTableColumn_row_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:didClickTableColumn:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_didClickTableColumn_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:didDragTableColumn:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_didDragTableColumn_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:heightOfRow:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_heightOfRow_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:isGroupRow:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_isGroupRow_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:mouseDownInHeaderOfTableColumn:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:nextTypeSelectMatchFromRow:toRow:forString:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_nextTypeSelectMatchFromRow_toRow_forString_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:selectionIndexesForProposedSelection:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldEditTableColumn:row:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldEditTableColumn_row_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldSelectRow:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectRow_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldSelectTableColumn:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectTableColumn_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldShowViewExpansionForTableColumn:row:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldShowViewExpansionForTableColumn_row_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldTrackView:forTableColumn:row:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTrackView_forTableColumn_row_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldTypeSelectForEvent:withCurrentSearchString:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTypeSelectForEvent_withCurrentSearchString_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:toolTipForView:rect:tableColumn:row:mouseLocation:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_toolTipForView_rect_tableColumn_row_mouseLocation_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:typeSelectStringForTableColumn:row:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_typeSelectStringForTableColumn_row_; - - if ([_outlineViewDelegate respondsToSelector:@selector(tableView:willDisplayView:forTableColumn:row:)]) - _implementedDelegateMethods |= CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_; -*/ + if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:willDisplayView:forTableColumn:item:)]) + _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_; + if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)]) [defaultCenter addObserver:_outlineViewDelegate @@ -491,6 +528,55 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ return [super frameOfDataViewAtColumn:aColumn row:aRow]; } +- (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex +{ + _retargetedItem = theItem; + _shouldRetargetItem = YES; + + _retargedChildIndex = theIndex; + _shouldRetargetChildIndex = YES; +} + +- (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset +{ + if (_shouldRetargetItem) + return _retargetedItem; + + var lowerLevel = [self levelForRow:theLowerRowIndex] + upperItem = [self itemAtRow:theUpperRowIndex]; + upperLevel = [self levelForItem:upperItem]; + + // If the row above us has a higher level the item can be added to multiple parent items + // Determine which one by looping through all possible parents and return the first + // of which the indentation level is larger than the current x offset + while (upperLevel > lowerLevel) + { + upperLevel = [self levelForItem:upperItem]; + + // See if this item's indentation level matches the mouse offset + if (theOffset.x > (upperLevel + 1) * [self indentationPerLevel]) + return [self parentForItem:upperItem]; + + // Check the next parent + upperItem = [self parentForItem:upperItem]; + } + + return [self parentForItem:[self itemAtRow:theLowerRowIndex]]; +} + +- (CPRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CPPoint)theOffset +{ + // Call super and the update x to reflect the current indentation level + var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset], + parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset], + level = [self levelForItem:parentItem]; + + rect.origin.x = (level + 1) * [self indentationPerLevel]; + rect.size.width -= rect.origin.x; // This assumes that the x returned by super is zero + + return rect; +} + - (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns { [super _loadDataViewsInRows:rows columns:columns]; @@ -626,6 +712,7 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem) { if (!anItem) return; + with(anOutlineView) { // Get the existing info if it exists. @@ -789,6 +876,93 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]]; } +- (BOOL)tableView:(CPTableView)aTableColumn writeRowsWithIndexes:(CPIndexSet)theIndexes toPasteboard:(CPPasteboard)thePasteboard +{ + if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_)) + return NO; + + var rowIndexes = []; + [theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil]; + + var rowIndex = [rowIndexes count], + items = []; + + while (rowIndex--) + [items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]]; + + return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard]; +} + +- (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset +{ + if (_outlineView._shouldRetargetChildIndex) + return _outlineView._retargedChildIndex; + + var childIndex = CPNotFound; + + if (theDropOperation === CPTableViewDropAbove) + { + var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset], + itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo, + children = itemInfo.children; + + childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]]; + + if (childIndex === CPNotFound) + childIndex = children.length; + } + else if (theDropOperation === CPTableViewDropOn) + childIndex = -1; + + return childIndex; +} + +- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset +{ + if (theDropOperation === CPTableViewDropAbove) + return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset] + + return [_outlineView itemAtRow:theRow]; +} + +- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo + proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation +{ + if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_)) + return CPDragOperationNone; + + // Make sure the retargeted item and index are reset + _outlineView._retargetedItem = nil; + _outlineView._shouldRetargetItem = NO; + + _outlineView._retargedChildIndex = nil; + _outlineView._shouldRetargetChildIndex = NO; + + var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil], + parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location]; + childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location]; + + return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex]; +} + +- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id )theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation +{ + if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_)) + return NO; + + var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil], + parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location]; + childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location]; + + _outlineView._retargetedItem = nil; + _outlineView._shouldRetargetItem = NO; + + _outlineView._retargedChildIndex = nil; + _outlineView._shouldRetargetChildIndex = NO; + + return [_outlineView._outlineViewDataSource outlineView:_outlineView acceptDrop:theInfo item:parentItem childIndex:childIndex]; +} + @end @implementation _CPOutlineViewTableViewDelegate : CPObject @@ -806,6 +980,48 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt return self; } +- (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow +{ + var dataView = nil; + + if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_)) + dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView + dataViewForTableColumn:theTableColumn + item:[_outlineView itemAtRow:theRow]]; + + if (!dataView) + dataView = [theTableColumn dataViewForRow:theRow]; + + return dataView; +} + +- (BOOL)tableView:(CPTableView)theTableView shouldSelectRow:(int)theRow +{ + if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_)) + return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]]; + + return YES; +} + +- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow +{ + if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_)) + return [_outlineView._outlineViewDelegate outlineView:_outlineView heightOfRowByItem:[_outlineView itemAtRow:theRow]]; + + return [theTableView rowHeight]; +} + +- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)aRowIndex +{ + if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_)) + { + var item = [_outlineView itemAtRow:aRowIndex]; + [_outlineView._outlineViewDelegate outlineView:_outlineView willDisplayView:aView forTableColumn:aTableColumn item:item]; + } +} + + + @end @implementation CPDisclosureButton : CPButton @@ -855,7 +1071,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt CGContextClosePath(context); - CGContextSetFillColor(context, ([self themeState] & CPThemeState("highlighted")) ? [CPColor blackColor] : [CPColor grayColor]); + CGContextSetFillColor(context, [self isHighlighted] ? [CPColor whiteColor] : [CPColor grayColor]); CGContextFillPath(context); } diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index b22ebd87b..6c3acc40e 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -83,7 +83,7 @@ CPTableColumnUserResizingMask = 1 << 1; [textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"]; [textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateHighlighted]; [textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateHighlighted]; - [textDataView setValue:CGInsetMake(4.0, 8.0, 0.0, 8.0) forThemeAttribute:@"content-inset"]; + [textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"]; [self setDataView:textDataView]; } diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index fdc58db0d..c6bc4f64a 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -883,6 +883,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return _selectedColumnIndexes; } +- (int)selectedRow +{ + return [_selectedRowIndexes lastIndex]; +} + - (CPIndexSet)selectedRowIndexes { return _selectedRowIndexes; @@ -1825,13 +1830,15 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (void)setDropRow:(CPInteger)row dropOperation:(CPTableViewDropOperation)operation { - if(row < 0 && operation === CPTableViewDropAbove) - row = 0; - - if(row >= [self numberOfRows] && operation === CPTableViewDropOn) - [CPException raise:CPInvalidArgumentException - reason:@"Attempt to set dropRow="+ row +", dropOperation=CPTableViewDropOn when [0 - "+ - [self numberOfRows] +"] is valid range of rows."]; + if(row > [self numberOfRows] && operation === CPTableViewDropOn) + { + var numberOfRows = [self numberOfRows] + 1; + var reason = @"Attempt to set dropRow=" + row + + " dropOperation=CPTableViewDropOn when [0 - " + numberOfRows + "] is valid range of rows." + + [[CPException exceptionWithName:@"Error" reason:reason userInfo:nil] raise]; + } + _retargetedDropRow = row; _retargetedDropOperation = operation; @@ -2076,7 +2083,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [dataView unsetThemeState:CPThemeStateHighlighted]; if (_implementedDelegateMethods & CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_) - [[self delegate] tableView:self willDisplayView:dataView forTableColumn:tableColumn row:row]; + [_delegate tableView:self willDisplayView:dataView forTableColumn:tableColumn row:row]; if ([dataView superview] !== self) [self addSubview:dataView]; @@ -2152,6 +2159,13 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (CPView)_newDataViewForRow:(CPInteger)aRow tableColumn:(CPTableColumn)aTableColumn { + if ((_implementedDelegateMethods & CPTableViewDelegate_tableView_dataViewForTableColumn_row_)) + { + var dataView = [_delegate tableView:self dataViewForTableColumn:aTableColumn row:aRow]; + [aTableColumn setDataView:dataView]; + } + + return [aTableColumn _newDataViewForRow:aRow]; } @@ -2591,16 +2605,16 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else _draggedRowIndexes = [CPIndexSet indexSetWithIndex:row]; + //ask the datasource for the data var pboard = [CPPasteboard pasteboardWithName:CPDragPboard]; - if ([self canDragRowsWithIndexes:_draggedRowIndexes atPoint:aPoint] && - [_dataSource tableView:self writeRowsWithIndexes:_draggedRowIndexes toPasteboard:pboard]) + if ([self canDragRowsWithIndexes:_draggedRowIndexes atPoint:aPoint] && [_dataSource tableView:self writeRowsWithIndexes:_draggedRowIndexes toPasteboard:pboard]) { var currentEvent = [CPApp currentEvent], offset = CPPointMakeZero(), tableColumns = [_tableColumns objectsAtIndexes:_exposedColumns]; - + // We deviate from the default Cocoa implementation here by asking for a view in stead of an image // We support both, but the view prefered over the image because we can mimic the rows we are dragging // by re-creating the data views for the dragged rows @@ -2608,33 +2622,27 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; tableColumns:tableColumns event:currentEvent offset:offset]; - + if (!view) { var image = [self dragImageForRowsWithIndexes:_draggedRowIndexes tableColumns:tableColumns event:currentEvent offset:offset]; - view = [[CPImageView alloc] initWithFrame:CPMakeRect(0, 0, [image size].width, [image size].height)]; [view setImage:image]; } - - var bounds = [view bounds], - viewLocation = CPPointMake(aPoint.x - CGRectGetWidth(bounds)/2 + offset.x, aPoint.y - CGRectGetHeight(bounds)/2 + offset.y); - - [self dragView:view - at:viewLocation - offset:CPPointMakeZero() - event:[CPApp currentEvent] - pasteboard:pboard - source:self - slideBack:YES]; - + + var bounds = [view bounds]; + var viewLocation = CPPointMake(aPoint.x - CGRectGetWidth(bounds)/2 + offset.x, aPoint.y - CGRectGetHeight(bounds)/2 + offset.y); + [self dragView:view at:viewLocation offset:CPPointMakeZero() event:[CPApp currentEvent] pasteboard:pboard source:self slideBack:YES]; _startTrackingPoint = nil; - + return NO; } + + // The delegate disallowed the drag so clear the dragged row indexes + _draggedRowIndexes = [CPIndexSet indexSet]; } else if (ABS(_startTrackingPoint.x - aPoint.x) < 5 && ABS(_startTrackingPoint.y - aPoint.y) < 5) return YES; @@ -2722,27 +2730,23 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self sendAction:_doubleAction to:_target]; } -/*! +/* @ignore */ - (CPDragOperation)draggingEntered:(id)sender { - var dropOperation = [self _proposedDropOperation], - draggingLocation = [sender draggingLocation], - row; + var location = [self convertPoint:[sender draggingLocation] fromView:nil], + dropOperation = [self _proposedDropOperationAtPoint:location], + row = [self _proposedRowAtPoint:location]; - var location = [self convertPoint:draggingLocation fromView:nil]; - - row = [self _proposedRowAtPoint:location]; - if(_retargetedDropRow !== nil) row = _retargetedDropRow; var draggedTypes = [self registeredDraggedTypes], count = [draggedTypes count], - i; + i = 0; - for (i = 0; i < count; i++) + for (; i < count; i++) { if ([[[sender draggingPasteboard] types] containsObject:[draggedTypes objectAtIndex: i]]) return [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation]; @@ -2785,14 +2789,26 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; /* @ignore */ -- (CPTableViewDropOperation)_proposedDropOperation +- (CPTableViewDropOperation)_proposedDropOperationAtPoint:(CGPoint)theDragPoint { - //check is something is forced... - // otherwise we use the above action by default - if(_retargetedDropOperation !== nil) + if(_retargetedDropOperation !== nil) return _retargetedDropOperation; - else - return CPTableViewDropAbove; + + var row = [self _proposedRowAtPoint:theDragPoint], + rowRect = [self rectOfRow:row]; + + // If there is no (the default) or to little inter cell spacing we create some room for the CPTableViewDropAbove indicator + // This probably doesn't work if the row height is smaller than or around 5.0 + if ([self intercellSpacing].height < 5.0) + rowRect = CPRectInset(rowRect, 0.0, 5.0 - [self intercellSpacing].height); + + // If the altered row rect contains the drag point we show the drop on + // We don't show the drop on indicator if we are dragging below the last row + // in that case we always want to show the drop above indicator + if (CGRectContainsPoint(rowRect, theDragPoint) && row < _numberOfRows) + return CPTableViewDropOn; + + return CPTableViewDropAbove; } /* @@ -2800,22 +2816,22 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPInteger)_proposedRowAtPoint:(CGPoint)dragPoint { - var numberOfRows = [self numberOfRows], - row; - // cocoa seems to jump to the next row when we approach the below row - dragPoint.y += FLOOR(_rowHeight/4); - - if (dragPoint.y > numberOfRows * (_rowHeight + _intercellSpacing.height)) - { - if ([self _proposedDropOperation] === CPTableViewDropAbove) - row = numberOfRows; - else - row = numberOfRows - 1; - } - else - row = [self rowAtPoint:dragPoint]; - - return row; + // We don't use rowAtPoint here because the drag indicator can appear below the last row + // and rowAtPoint doesn't return rows that are larger than numberOfRows + var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )); + + // Determine if the mouse is currently closer to this row or the row below it + var lowerRow = row + 1, + rect = [self rectOfRow:row], + lowerRect = [self rectOfRow:lowerRow]; + + if (ABS(CPRectGetMinY(lowerRect) - dragPoint.y) < ABS(dragPoint.y - CPRectGetMinY(rect))) + row = lowerRow; + + if (row >= [self numberOfRows]) + row = [self numberOfRows]; + + return row; } - (void)_validateDrop:(id)info proposedRow:(CPInteger)row proposedDropOperation:(CPTableViewDropOperation)dropOperation @@ -2826,37 +2842,53 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return CPDragOperationNone; } +- (CPRect)_rectForDropHighlightViewOnRow:(int)theRowIndex +{ + if (theRowIndex >= [self numberOfRows]) + theRowIndex = [self numberOfRows] - 1; + + return [self rectOfRow:theRowIndex]; +} + +- (CPRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CPPoint)theOffset +{ + if (theLowerRowIndex > [self numberOfRows]) + theLowerRowIndex = [self numberOfRows]; + + return [self rectOfRow:theLowerRowIndex]; +} + - (CPDragOperation)draggingUpdated:(id)sender { - var dropOperation = [self _proposedDropOperation], - numberOfRows = [self numberOfRows], - draggingLocation = [sender draggingLocation], - dragOperation, - row; + var location = [self convertPoint:[sender draggingLocation] fromView:nil], + dropOperation = [self _proposedDropOperationAtPoint:location], + numberOfRows = [self numberOfRows]; - var location = [self convertPoint:draggingLocation fromView:nil]; - - row = [self _proposedRowAtPoint:location]; - dragOperation = [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation]; - + var row = [self _proposedRowAtPoint:location], + dragOperation = [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation]; + exposedClipRect = [self exposedClipRect]; + if(_retargetedDropRow !== nil) row = _retargetedDropRow; - //if the user forces -1 then we should highlight the whole tabelview - var rowRect; - if(_retargetedDropRow === -1) - rowRect = [self exposedClipRect]; - else - rowRect = [self rectOfRow:row]; - var exposedClipRect = [self exposedClipRect]; - var visibleWidth = _CGRectGetWidth(exposedClipRect); + if (dropOperation === CPTableViewDropOn && row >= [self numberOfRows]) + row = [self numberOfRows] - 1; - rowRect = _CGRectMake(_CGRectGetMinX(exposedClipRect), rowRect.origin.y, visibleWidth, rowRect.size.height); - - [_dropOperationFeedbackView setDropOperation:dropOperation]; + var rect = CPRectMakeZero(); + + if (row === -1) + rect = exposedClipRect; + + else if (dropOperation === CPTableViewDropAbove) + rect = [self _rectForDropHighlightViewBetweenUpperRow:row - 1 andLowerRow:row offset:location]; + + else + rect = [self _rectForDropHighlightViewOnRow:row]; + + [_dropOperationFeedbackView setDropOperation:row !== -1 ? dropOperation : CPDragOperationNone]; [_dropOperationFeedbackView setHidden:(dragOperation == CPDragOperationNone)]; - [_dropOperationFeedbackView setFrame:rowRect]; + [_dropOperationFeedbackView setFrame:rect]; [_dropOperationFeedbackView setCurrentRow:row]; [self addSubview:_dropOperationFeedbackView]; @@ -2887,15 +2919,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (BOOL)performDragOperation:(id)sender { - var operation = [self _proposedDropOperation], - draggingLocation = [sender draggingLocation]; + var location = [self convertPoint:[sender draggingLocation] fromView:nil]; + operation = [self _proposedDropOperationAtPoint:location], + row = _retargetedDropRow; - var location = [self convertPoint:draggingLocation fromView:nil]; - - if(_retargetedDropRow !== nil) - var row = _retargetedDropRow; - else - var row = [self rowAtPoint:location] - 1; + if(row === nil) + var row = [self _proposedRowAtPoint:location]; return [_dataSource tableView:self acceptDrop:sender row:row dropOperation:operation]; } @@ -3212,8 +3241,8 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", _selectedColumnIndexes = [CPIndexSet indexSet]; _selectedRowIndexes = [CPIndexSet indexSet]; - [self setDataSource:[aCoder decodeObjectForKey:CPTableViewDataSourceKey]]; - [self setDelegate:[aCoder decodeObjectForKey:CPTableViewDelegateKey]]; + _dataSource = [aCoder decodeObjectForKey:CPTableViewDataSourceKey]; + _delegate = [aCoder decodeObjectForKey:CPTableViewDelegateKey]; _tableDrawView = [[_CPTableDrawView alloc] initWithTableView:self]; [_tableDrawView setBackgroundColor:[CPColor clearColor]]; @@ -3303,17 +3332,23 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", { if(tableView._destinationDragStyle === CPTableViewDraggingDestinationFeedbackStyleNone) return; - + var context = [[CPGraphicsContext currentContext] graphicsPort]; CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"4886ca"]); CGContextSetLineWidth(context, 3); - - if(dropOperation === CPTableViewDropOn) + + if (currentRow === -1) + { + CGContextStrokeRect(context, [self bounds]); + } + + else if (dropOperation === CPTableViewDropOn) { //if row is selected don't fill and stroke white - var selectedRows = [tableView selectedRowIndexes]; - var newRect = _CGRectMake(aRect.origin.x + 2, aRect.origin.y + 2, aRect.size.width - 4, aRect.size.height - 5); + var selectedRows = [tableView selectedRowIndexes], + newRect = _CGRectMake(aRect.origin.x + 2, aRect.origin.y + 2, aRect.size.width - 4, aRect.size.height - 5); + if([selectedRows containsIndex:currentRow]) { CGContextSetLineWidth(context, 2); @@ -3326,13 +3361,9 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", } CGContextStrokeRoundedRectangleInRect(context, newRect, 8, YES, YES, YES, YES); - } - - - if(dropOperation === CPTableViewDropAbove) + } + else if (dropOperation === CPTableViewDropAbove) { - - //reposition the view up a tad [self setFrameOrigin:CGPointMake(_frame.origin.x, _frame.origin.y - 8)]; @@ -3365,5 +3396,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", CGContextStrokePath(context); //CGContextStrokeLineSegments(context, [aRect.origin.x + 8, aRect.origin.y + 8, 300 , aRect.origin.y + 8]); } + + } @end diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index b3c452cc0..e70984296 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -683,9 +683,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)setObjectValue:(id)aValue { [super setObjectValue:aValue]; - + #if PLATFORM(DOM) - if (CPTextFieldInputOwner === self) + + if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self) [self _inputElement].value = aValue; #endif diff --git a/AppKit/CPViewController.j b/AppKit/CPViewController.j index c66f021f8..3fffe261d 100644 --- a/AppKit/CPViewController.j +++ b/AppKit/CPViewController.j @@ -138,8 +138,6 @@ var CPViewControllerCachedCibs; Returns the view that the controller manages. If this property is nil, the controller sends loadView to itself to create the view that it manages. Subclasses should override the loadView method to create any custom views. The default value is nil. - - Note: An error will not be thrown if after -loadView, the view property is still nil. -view will simply return nil, but will continue to call -loadView on subsequent calls. */ - (CPView)view { @@ -155,14 +153,34 @@ var CPViewControllerCachedCibs; if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]]) [self setView:[cibOwner valueForKey:@"view"]]; + if (!_view) + { + var reason = [CPString stringWithFormat:@"View for %@ could not be loaded from Cib or no view specified. Override loadView to load the view manually.", self]; + + [CPException raise:CPInternalInconsistencyException reason:reason]; + } + if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)]) [cibOwner viewControllerDidLoadCib:self]; + + [self viewDidLoad]; } return _view; } +/*! + This method is called after the view controller has loaded its associated views into memory. + This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method. + This method is most commonly used to perform additional initialization steps on views that are loaded from nib files. +*/ +- (void)viewDidLoad +{ + +} + + /*! Manually sets the view that the controller manages. Setting to nil will cause -loadView to be called on all subsequent calls of -view. diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 3f506889d..e68c33174 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -175,6 +175,8 @@ CPWindowBelow = 2; CPWindowWillCloseNotification = @"CPWindowWillCloseNotification"; CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification"; CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification"; +CPWindowDidBecomeKeyNotification = @"CPWindowDidBecomeKeyNotification"; +CPWindowDidResignKeyNotification = @"CPWindowDidResignKeyNotification"; CPWindowDidResizeNotification = @"CPWindowDidResizeNotification"; CPWindowDidMoveNotification = @"CPWindowDidMoveNotification"; CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification"; @@ -762,12 +764,7 @@ CPTexturedBackgroundWindowMask [_platformWindow order:CPWindowOut window:self relativeTo:nil]; - if ([CPApp keyWindow] == self) - { - [self resignKeyWindow]; - - CPApp._keyWindow = nil; - } + [self _updateMainAndKeyWindows]; } /*! @@ -1066,13 +1063,31 @@ CPTexturedBackgroundWindowMask */ - (void)setDelegate:(id)aDelegate { - // FIXME: Unregister for notifications! + var defaultCenter = [CPNotificationCenter defaultCenter]; + + [defaultCenter removeObserver:_delegate name:CPWindowDidResignKeyNotification object:self]; + [defaultCenter removeObserver:_delegate name:CPWindowDidBecomeKeyNotification object:self]; + [defaultCenter removeObserver:_delegate name:CPWindowDidBecomeMainNotification object:self]; + [defaultCenter removeObserver:_delegate name:CPWindowDidResignMainNotification object:self]; + [defaultCenter removeObserver:_delegate name:CPWindowDidMoveNotification object:self]; + [defaultCenter removeObserver:_delegate name:CPWindowDidResizeNotification object:self]; _delegate = aDelegate; - _delegateRespondsToWindowWillReturnUndoManagerSelector = [_delegate respondsToSelector:@selector(windowWillReturnUndoManager:)]; - var defaultCenter = [CPNotificationCenter defaultCenter]; + if ([_delegate respondsToSelector:@selector(windowDidResignKey:)]) + [defaultCenter + addObserver:_delegate + selector:@selector(windowDidResignKey:) + name:CPWindowDidResignKeyNotification + object:self]; + + if ([_delegate respondsToSelector:@selector(windowDidBecomeKey:)]) + [defaultCenter + addObserver:_delegate + selector:@selector(windowDidBecomeKey:) + name:CPWindowDidBecomeKeyNotification + object:self]; if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)]) [defaultCenter @@ -1418,8 +1433,14 @@ CPTexturedBackgroundWindowMask */ - (void)becomeKeyWindow { - if (_firstResponder != self && [_firstResponder respondsToSelector:@selector(becomeKeyWindow)]) + CPApp._keyWindow = self; + + if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(becomeKeyWindow)]) [_firstResponder becomeKeyWindow]; + + [[CPNotificationCenter defaultCenter] + postNotificationName:CPWindowDidBecomeKeyNotification + object:self]; } /*! @@ -1456,13 +1477,10 @@ CPTexturedBackgroundWindowMask */ - (void)makeKeyWindow { - if (![self canBecomeKeyWindow]) + if ([CPApp keyWindow] === self || ![self canBecomeKeyWindow]) return; - [CPApp._keyWindow resignKeyWindow]; - - CPApp._keyWindow = self; - + [[CPApp keyWindow] resignKeyWindow]; [self becomeKeyWindow]; } @@ -1473,9 +1491,12 @@ CPTexturedBackgroundWindowMask { if (_firstResponder != self && [_firstResponder respondsToSelector:@selector(resignKeyWindow)]) [_firstResponder resignKeyWindow]; - - if ([_delegate respondsToSelector:@selector(windowDidResignKey:)]) - [_delegate windowDidResignKey:self]; + + CPApp._keyWindow = nil; + + [[CPNotificationCenter defaultCenter] + postNotificationName:CPWindowDidResignKeyNotification + object:self]; } /*! @@ -1664,6 +1685,8 @@ CPTexturedBackgroundWindowMask [[self platformWindow] miniaturize:sender]; + [self _updateMainAndKeyWindows]; + [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMiniaturizeNotification object:self]; _isMiniaturized = YES; @@ -1799,13 +1822,10 @@ CPTexturedBackgroundWindowMask */ - (void)makeMainWindow { - if (CPApp._mainWindow === self || ![self canBecomeMainWindow]) + if ([CPApp mainWindow] === self || ![self canBecomeMainWindow]) return; - [CPApp._mainWindow resignMainWindow]; - - CPApp._mainWindow = self; - + [[CPApp mainWindow] resignMainWindow]; [self becomeMainWindow]; } @@ -1814,9 +1834,11 @@ CPTexturedBackgroundWindowMask */ - (void)becomeMainWindow { + CPApp._mainWindow = self; + [self _synchronizeMenuBarTitleWithWindowTitle]; [self _synchronizeSaveMenuWithDocumentSaving]; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidBecomeMainNotification object:self]; @@ -1830,6 +1852,71 @@ CPTexturedBackgroundWindowMask [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidResignMainNotification object:self]; + + CPApp._mainWindow = nil; +} + +- (void)_updateMainAndKeyWindows +{ + var allWindows = [CPApp orderedWindows], + windowCount = [allWindows count]; + + if (!windowCount) + return; + + if ([self isKeyWindow]) + { + var keyWindow = [CPApp keyWindow]; + [self resignKeyWindow]; + + if (keyWindow && keyWindow !== self && [keyWindow canBecomeKeyWindow]) + [keyWindow makeKeyWindow]; + else + { + var menuWindow = [CPApp mainMenu]._menuWindow; + for (var i = 0; i < windowCount; i++) + { + var currentWindow = allWindows[i]; + if (currentWindow === self || currentWindow === menuWindow) + continue; + + if ([currentWindow isVisible] && [currentWindow canBecomeKeyWindow]) + { + [currentWindow makeKeyWindow]; + break; + } + } + + if (![CPApp keyWindow]) + [keyWindow makeKeyWindow]; + } + } + + + if ([self isMainWindow]) + { + var mainWindow = [CPApp mainWindow]; + [self resignMainWindow]; + + if (mainWindow && mainWindow !== self && [mainWindow canBecomeMainWindow]) + [mainWindow makeMainWindow]; + else + { + var menuWindow = [CPApp mainMenu]._menuWindow; + for (var i = 0; i < windowCount; i++) + { + var currentWindow = allWindows[i]; + if (currentWindow === self || currentWindow === menuWindow) + continue; + + if ([currentWindow isVisible] && [currentWindow canBecomeMainWindow]) + { + [currentWindow makeMainWindow]; + break; + } + } + } + } } // Managing Toolbars diff --git a/AppKit/Platform/CPPlatform.j b/AppKit/Platform/CPPlatform.j index 8bf37856e..db2128810 100644 --- a/AppKit/Platform/CPPlatform.j +++ b/AppKit/Platform/CPPlatform.j @@ -58,6 +58,10 @@ { } ++ (void)deactivate +{ +} + + (void)hideOtherApplications:(id)aSender { } diff --git a/AppKit/Platform/DOM/CPPlatform.j b/AppKit/Platform/DOM/CPPlatform.j index 96c7a30bf..98d7ca02e 100644 --- a/AppKit/Platform/DOM/CPPlatform.j +++ b/AppKit/Platform/DOM/CPPlatform.j @@ -69,6 +69,12 @@ var screenNeedsInitialization = NO, window.cpActivateIgnoringOtherApps(!!shouldIgnoreOtherApps); } ++ (void)deactivate +{ + if (typeof window["cpDeactivate"] === "function") + window.cpDeactivate(); +} + + (void)hideOtherApplications:(id)aSender { if (typeof window["cpHideOtherApplications"] === "function") diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index e6cff4912..1e7f8d835 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -426,7 +426,14 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; + (CPSet)visiblePlatformWindows { - return PlatformWindows; + if ([[CPPlatformWindow primaryPlatformWindow] isVisible]) + { + var set = [CPSet setWithSet:PlatformWindows]; + [set addObject:[CPPlatformWindow primaryPlatformWindow]]; + return set; + } + else + return PlatformWindows; } - (void)orderFront:(id)aSender @@ -1374,19 +1381,25 @@ var CPDOMEventStop = function(aDOMEvent, aPlatformWindow) function CPWindowObjectList() { - var platformWindow = [CPPlatformWindow primaryPlatformWindow], - levels = platformWindow._windowLevels, - layers = platformWindow._windowLayers, - levelCount = levels.length, + var platformWindows = [CPPlatformWindow visiblePlatformWindows], + platformWindowEnumerator = [platformWindows objectEnumerator], + platformWindow = nil, windowObjects = []; - while (levelCount--) + while (platformWindow = [platformWindowEnumerator nextObject]) { - var windows = [layers objectForKey:levels[levelCount]]._windows, - windowCount = windows.length; + var levels = platformWindow._windowLevels, + layers = platformWindow._windowLayers, + levelCount = levels.length; - while (windowCount--) - windowObjects.push(windows[windowCount]); + while (levelCount--) + { + var windows = [layers objectForKey:levels[levelCount]]._windows, + windowCount = windows.length; + + while (windowCount--) + windowObjects.push(windows[windowCount]); + } } return windowObjects; @@ -1394,20 +1407,11 @@ function CPWindowObjectList() function CPWindowList() { - var platformWindow = [CPPlatformWindow primaryPlatformWindow], - levels = platformWindow._windowLevels, - layers = platformWindow._windowLayers, - levelCount = levels.length, - windowNumbers = []; + var windowObjectList = CPWindowObjectList(), + windowList = []; - while (levelCount--) - { - var windows = [layers objectForKey:levels[levelCount]]._windows, - windowCount = windows.length; + for (var i = 0, count = [windowObjectList count]; i < count; i++) + windowList.push([windowObjectList[i] windowNumber]); - while (windowCount--) - windowNumbers.push([windows[windowCount] windowNumber]); - } - - return windowNumbers; + return windowList; } diff --git a/Tests/Manual/CPOutlineViewTest/AppController.j b/Tests/Manual/CPOutlineViewTest/AppController.j new file mode 100644 index 000000000..8e080afc7 --- /dev/null +++ b/Tests/Manual/CPOutlineViewTest/AppController.j @@ -0,0 +1,309 @@ +/* + * AppController.j + * outlineview + * + * Created by You on January 22, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +@import +@import + +CPLogRegister(CPLogConsole); + +CustomOutlineViewDragType = @"CustomOutlineViewDragType"; + +@implementation Menu : CPObject +{ + Menu _menu @accessors(property=menu); + + CPString _title @accessors(property=title); + CPArray _children @accessors(property=children); +} + ++ (id)menuWithTitle:(CPString)theTitle +{ + return [[self alloc] initWithTitle:theTitle]; +} + ++ (id)menuWithTitle:(CPString)theTitle children:(CPArray)theChildren +{ + return [[self alloc] initWithTitle:theTitle children:theChildren]; +} + +- (id)initWithTitle:(CPString)theTitle +{ + return [self initWithTitle:theTitle children:nil]; +} + +- (id)initWithTitle:(CPString)theTitle children:(CPArray)theChildren +{ + if ((self = [super init])) + { + _title = theTitle; + [self setChildren:theChildren]; + } + + return self; +} + +- (CPString)description +{ + return [self title]; +} + +- (void)insertSubmenu:(Menu)theItem atIndex:(int)theIndex +{ + // CPLog.debug(@"insert menu: %@ in menu: %@ at index: %i", theItem, self, theIndex); + + if ([[self children] containsObject:theItem]) + return; + + if ([theItem menu]) + [theItem removeFromMenu]; + + [theItem setMenu:self]; + + if (theIndex === -1) + { + [[self children] addObject:theItem]; + } + else + { + [[self children] insertObject:theItem atIndex:theIndex]; + } + + // CPLog.debug(@"%@ children: %@", self, [self children]); +} + +- (void)removeFromMenu +{ + // CPLog.debug(@"remove menu: %@ from menu: %@", self, [self menu]); + + [[[self menu] children] removeObject:self]; + + CPLog.debug([[self menu] children]); + + [self setMenu:nil]; +} + +- (void)setChildren:(CPArray)theChildren +{ + if (theChildren === nil) + theChildren = []; + + if (_children === theChildren) + return; + + var childIndex = [theChildren count]; + while (childIndex--) + { + var child = theChildren[childIndex]; + [child setMenu:self]; + } + + _children = theChildren; +} + +- (id)initWithCoder:(CPCoder)theCoder +{ + if (self = [super init]) + { + _menu = [theCoder decodeObjectForKey:@"MenuSuperMenuKey"]; + _title = [theCoder decodeObjectForKey:@"MenuTitleKey"]; + [self setChildren:[theCoder decodeObjectForKey:@"MenuChildrenKey"]]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [aCoder encodeObject:_menu forKey:@"MenuSuperMenuKey"]; + [aCoder encodeObject:_title forKey:@"MenuTitleKey"]; + [aCoder encodeObject:_children forKey:@"MenuChildrenKey"]; +} + +@end + +@implementation AppController : CPObject +{ + Menu _menu @accessors(property=menu); + CPOutlineView _outlineView; + + CPArray _draggedItems; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + _menu = [Menu menuWithTitle:@"Top" children:[ + [Menu menuWithTitle:@"1" children:[ + [Menu menuWithTitle:@"1.1" children:[ + [Menu menuWithTitle:@"1.1.1"], + [Menu menuWithTitle:@"1.1.2"], + ]], + [Menu menuWithTitle:@"1.2" children:[ + [Menu menuWithTitle:@"1.2.1" children:[ + [Menu menuWithTitle:@"1.2.1.1"], + [Menu menuWithTitle:@"1.2.1.2"], + [Menu menuWithTitle:@"1.2.1.3"], + ]], + [Menu menuWithTitle:@"1.2.2"], + [Menu menuWithTitle:@"1.2.3"] + ]] + ]], + // [Menu menuWithTitle:@"2" children:[ + // [Menu menuWithTitle:@"2.1" children:[ + // [Menu menuWithTitle:@"2.1.1"], + // [Menu menuWithTitle:@"2.1.2"], + // [Menu menuWithTitle:@"2.1.3"], + // ]], + // [Menu menuWithTitle:@"2.2" children:[ + // [Menu menuWithTitle:@"2.2.1"], + // [Menu menuWithTitle:@"2.2.2"], + // ]] + // ]], + // [Menu menuWithTitle:@"3" children:[ + // [Menu menuWithTitle:@"3.1" children:[ + // [Menu menuWithTitle:@"3.1.1"], + // [Menu menuWithTitle:@"3.1.2"], + // [Menu menuWithTitle:@"3.1.3"], + // ]], + // [Menu menuWithTitle:@"3.2" children:[ + // [Menu menuWithTitle:@"3.2.1"], + // [Menu menuWithTitle:@"3.2.2"], + // [Menu menuWithTitle:@"3.2.3"], + // [Menu menuWithTitle:@"3.2.4"], + // ]], + // [Menu menuWithTitle:@"3.3" children:[ + // [Menu menuWithTitle:@"3.3.1"], + // [Menu menuWithTitle:@"3.3.2"], + // [Menu menuWithTitle:@"3.3.3"], + // [Menu menuWithTitle:@"3.3.4"], + // [Menu menuWithTitle:@"3.3.5"], + // ]] + // ]] + ]]; + + var scrollView = [[CPScrollView alloc] initWithFrame:[contentView bounds]]; + + + _outlineView = [[CPOutlineView alloc] initWithFrame:[contentView bounds]]; + + var column = [[CPTableColumn alloc] initWithIdentifier:@"One"]; + [_outlineView addTableColumn:column]; + [_outlineView setOutlineTableColumn:column]; + + [_outlineView addTableColumn:[[CPTableColumn alloc] initWithIdentifier:@"Two"]]; + + [_outlineView registerForDraggedTypes:[CustomOutlineViewDragType]]; + + [_outlineView setDataSource:self]; + [_outlineView setAllowsMultipleSelection:YES]; + [_outlineView expandItem:nil expandChildren:YES]; + // [_outlineView setRowHeight:50.0]; + // [_outlineView setIntercellSpacing:CPSizeMake(0.0, 10.0)] + + [scrollView setDocumentView:_outlineView]; + [theWindow setContentView:scrollView]; + + // [theWindow setContentView:_outlineView]; + + [theWindow orderFront:self]; + + [column setWidth:CPRectGetWidth([_outlineView bounds])]; +} + +- (id)outlineView:(CPOutlineView)theOutlineView child:(int)theIndex ofItem:(id)theItem +{ + if (theItem === nil) + theItem = [self menu]; + + // CPLog.debug(@"child: %i ofItem:%@ : %@", theIndex, theItem, [[theItem children] objectAtIndex:theIndex]); + + return [[theItem children] objectAtIndex:theIndex]; +} + +- (BOOL)outlineView:(CPOutlineView)theOutlineView isItemExpandable:(id)theItem +{ + if (theItem === nil) + theItem = [self menu]; + + // CPLog.debug(@"isItemExpandable:%@ : %@", theItem, [[theItem children] count] > 0); + + return [[theItem children] count] > 0; +} + +- (int)outlineView:(CPOutlineView)theOutlineView numberOfChildrenOfItem:(id)theItem +{ + if (theItem === nil) + theItem = [self menu]; + + // CPLog.debug(@"numberOfChildrenOfItem:%@ : %i", theItem, [[theItem children] count]); + + return [[theItem children] count]; +} + +- (id)outlineView:(CPOutlineView)anOutlineView objectValueForTableColumn:(CPTableColumn)theColumn byItem:(id)theItem +{ + // if ([theColumn identifier] === @"Two") + // return @"Two"; + + if (theItem === nil) + theItem = [self menu]; + + // CPLog.debug(@"objectValueForTableColumn:%@ byItem:%@ : %@", theColumn, theItem, [theItem title]); + + return [theItem title]; +} + +- (BOOL)outlineView:(CPOutlineView)anOutlineView writeItems:(CPArray)theItems toPasteboard:(CPPasteBoard)thePasteBoard +{ + _draggedItems = theItems; + [thePasteBoard declareTypes:[CustomOutlineViewDragType] owner:self]; + [thePasteBoard setData:[CPKeyedArchiver archivedDataWithRootObject:theItems] forType:CustomOutlineViewDragType]; + + return YES; +} + +- (CPDragOperation)outlineView:(CPOutlineView)anOutlineView validateDrop:(id < CPDraggingInfo >)theInfo proposedItem:(id)theItem proposedChildIndex:(int)theIndex +{ + CPLog.debug(@"validate item: %@ at index: %i", theItem, theIndex); + + if (theItem === nil) + [anOutlineView setDropItem:nil dropChildIndex:theIndex]; + + [anOutlineView setDropItem:theItem dropChildIndex:theIndex]; + + return CPDragOperationEvery; +} + +- (BOOL)outlineView:(CPOutlineView)outlineView acceptDrop:(id < CPDraggingInfo >)theInfo item:(id)theItem childIndex:(int)theIndex +{ + if (theItem === nil) + theItem = [self menu]; + + // CPLog.debug(@"drop item: %@ at index: %i", theItem, theIndex); + + var menuIndex = [_draggedItems count]; + while (menuIndex--) + { + var menu = [_draggedItems objectAtIndex:menuIndex]; + + // CPLog.debug(@"move item: %@ to: %@ index: %@", menu, theItem, theIndex); + + if (menu === theItem) + continue; + + [menu removeFromMenu]; + [theItem insertSubmenu:menu atIndex:theIndex]; + theIndex += 1; + } + + return YES; +} + +@end diff --git a/Tests/Manual/CPOutlineViewTest/Info.plist b/Tests/Manual/CPOutlineViewTest/Info.plist new file mode 100644 index 000000000..64faa0026 --- /dev/null +++ b/Tests/Manual/CPOutlineViewTest/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + outlineview + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/CPOutlineViewTest/Jakefile b/Tests/Manual/CPOutlineViewTest/Jakefile new file mode 100644 index 000000000..3a5432575 --- /dev/null +++ b/Tests/Manual/CPOutlineViewTest/Jakefile @@ -0,0 +1,38 @@ +/* + * Jakefile + * outlineview + * + * Created by You on January 22, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + task = require("jake").task, + FileList = require("jake").FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug"; + +app ("outlineview", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "outlineview.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("outlineview"); + task.setIdentifier("com.yourcompany.outlineview"); + task.setVersion("1.0"); + task.setAuthor("Your Company"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("outlineview"); + task.setSources(new FileList("**/*.j")); + task.setResources(new FileList("Resources/*")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["outlineview"]); diff --git a/Tests/Manual/CPOutlineViewTest/Resources/spinner.gif b/Tests/Manual/CPOutlineViewTest/Resources/spinner.gif new file mode 100644 index 000000000..06dbc2bc2 Binary files /dev/null and b/Tests/Manual/CPOutlineViewTest/Resources/spinner.gif differ diff --git a/Tests/Manual/CPOutlineViewTest/index-debug.html b/Tests/Manual/CPOutlineViewTest/index-debug.html new file mode 100644 index 000000000..30fd821ac --- /dev/null +++ b/Tests/Manual/CPOutlineViewTest/index-debug.html @@ -0,0 +1,84 @@ + + + + + + + + outlineview + + + + + + + + + + + + + + +
+ + + +
+ + + diff --git a/Tests/Manual/CPOutlineViewTest/index.html b/Tests/Manual/CPOutlineViewTest/index.html new file mode 100644 index 000000000..e0a035c11 --- /dev/null +++ b/Tests/Manual/CPOutlineViewTest/index.html @@ -0,0 +1,69 @@ + + + + + + + + outlineview + + + + + + + + + + + + +
+ + + +
+ + + + diff --git a/Tests/Manual/CPOutlineViewTest/main.j b/Tests/Manual/CPOutlineViewTest/main.j new file mode 100644 index 000000000..c35f7b26c --- /dev/null +++ b/Tests/Manual/CPOutlineViewTest/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * outlineview + * + * Created by You on January 22, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +}