From 8f1191733beaf0f402018240804298bcfe8c1cf1 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 19 Jan 2016 23:12:11 -0800 Subject: [PATCH] Fixed race condition when editing table cells Previously, when double-clicking on a table cell to edit it, there was a possibility of a race condition. A refresh of the display was requested, then the run loop was passed through once. But it was possible for the display refresh to not be queued when the run loop was passed through, in which case the refresh would cancel the editing. Or at least I think that's what was happening. ;-) This commit (hopefully) eliminates the race condition by synchronously refreshing the layout and display. Made some miscellaneous formatting fixes as well. --- AppKit/CPTableView.j | 28 +++++++++++++++++----------- AppKit/CPTextField.j | 6 ++++-- AppKit/CPView.j | 25 ++++++++++++++----------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 0762c2b9d..9b6ea2272 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -644,12 +644,8 @@ NOT YET IMPLEMENTED }]; } -// Reloads the views AND the data -- (void)_reloadDataViews +- (void)_setupReload { - //if (!_dataSource) - // return; - _reloadAllRows = YES; _objectValues = { }; _cachedRowHeights = []; @@ -661,11 +657,24 @@ NOT YET IMPLEMENTED // This updates the size too. [self noteNumberOfRowsChanged]; +} +// Reloads the views AND the data +- (void)_reloadDataViews +{ + [self _setupReload]; [self setNeedsLayout]; [self setNeedsDisplay:YES]; } +// Reloads the views AND the data +- (void)_reloadDataViewsSynchronously +{ + [self _setupReload]; + [self layout]; + [self display]; +} + //Target-action Behavior /*! Sets the message sent to the target when the user double-clicks an @@ -4680,7 +4689,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad { if ([self _sendDelegateShouldEditTableColumn:column row:rowIndex]) { - [self editColumn:columnIndex row:rowIndex withEvent:nil select:YES]; + [self editColumn:columnIndex row:rowIndex withEvent:[CPApp currentEvent] select:YES]; return; } } @@ -5303,6 +5312,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad if ([aView isKindOfClass:[CPTextField class]]) [aView setBezeled:editingState]; } + /*! Edits the dataview at a given row and column. This method is usually invoked automatically and should rarely be invoked directly The row at supplied rowIndex must be selected otherwise an exception is thrown. @@ -5317,11 +5327,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad if (![self isRowSelected:rowIndex]) [[CPException exceptionWithName:@"Error" reason:@"Attempt to edit row " + rowIndex + " when not selected." userInfo:nil] raise]; - [self reloadData]; - - // Process all events immediately to make sure table data views are reloaded. - [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; - + [self _reloadDataViewsSynchronously]; [self scrollRowToVisible:rowIndex]; [self scrollColumnToVisible:columnIndex]; diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 09ed728f4..98ba7eaa7 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -94,7 +94,8 @@ function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resig inputElement.focus(); [owner _restorePreviousScrollingOrigin:previousScrollingOrigin]; - } argument:nil order:0 modes:[CPDefaultRunLoopMode]]; + } + argument:nil order:0 modes:[CPDefaultRunLoopMode]]; } } @@ -838,6 +839,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [self _resignFirstKeyResponder]; _isEditing = NO; + if ([self isEditable]) { [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:@{"CPTextMovement": [self _currentTextMovement]}]]; @@ -1213,7 +1215,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)textDidFocus:(CPNotification)note { // this looks to prevent false propagation of notifications for other objects - if ([note object] != self) + if ([note object] !== self) return; if (_implementedDelegateMethods & CPTextFieldDelegate_controlTextDidFocus_) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 5b8d66007..f2ae7bb74 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -2684,20 +2684,23 @@ setBoundsOrigin: return _needsLayout; } +- (void)layout +{ + _needsLayout = NO; + + if (_viewClassFlags & CPViewHasCustomViewWillLayout) + [self viewWillLayout]; + + if (_viewClassFlags & CPViewHasCustomLayoutSubviews) + [self layoutSubviews]; + + [self viewDidLayout]; +} + - (void)layoutIfNeeded { if (_needsLayout) - { - _needsLayout = NO; - - if (_viewClassFlags & CPViewHasCustomViewWillLayout) - [self viewWillLayout]; - - if (_viewClassFlags & CPViewHasCustomLayoutSubviews) - [self layoutSubviews]; - - [self viewDidLayout]; - } + [self layout]; } /*!