Fix drag and drop of file objects - invoke cleanUpAfterDragOperation on lastDragView on NSWindow and add cleanup code to cleanUpAfterDragOperation in NSTextView

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/branches/gnustep_testplant_branch@35896 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Marcian Lytwyn 2012-12-15 04:50:05 +00:00
parent 09efaeba41
commit 43a41c50fc
2 changed files with 147 additions and 114 deletions

View file

@ -513,8 +513,7 @@ this happens when layout has been invalidated, and when we are resized.
[self sizeToFit]; [self sizeToFit];
/* TODO: we don't have to redisplay the entire view */ /* TODO: we don't have to redisplay the entire view */
[self setNeedsDisplay: YES]; [self setNeedsDisplay: YES];
[self updateInsertionPointStateAndRestartTimer: [self updateInsertionPointStateAndRestartTimer: [self shouldDrawInsertionPoint]];
[self shouldDrawInsertionPoint]];
[self _updateInputMethodState]; [self _updateInputMethodState];
/* In case any sections of text with custom cursors were moved */ /* In case any sections of text with custom cursors were moved */
[[self window] invalidateCursorRectsForView: self]; [[self window] invalidateCursorRectsForView: self];
@ -4111,132 +4110,156 @@ Figure out how the additional layout stuff is supposed to work.
return nil; return nil;
} }
- (void) _stopInsertionTimer
{
if (_insertionPointTimer)
{
[_insertionPointTimer invalidate];
DESTROY(_insertionPointTimer);
}
}
- (void) _startInsertionTimer
{
if (_insertionPointTimer)
{
NSWarnMLog(@"Starting insertion timer with existing one running");
[self _stopInsertionTimer];
}
_insertionPointTimer = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector: @selector(_blink:)
userInfo: nil
repeats: YES];
RETAIN(_insertionPointTimer);
}
- (void) updateInsertionPointStateAndRestartTimer: (BOOL)restartFlag - (void) updateInsertionPointStateAndRestartTimer: (BOOL)restartFlag
{ {
NSRect new; NSRect new;
if (!_layoutManager) if (!_layoutManager)
{ {
_insertionPointRect = NSZeroRect; _insertionPointRect = NSZeroRect;
return; return;
} }
// If we are in the middle of a dragging operation...
if (_dragTargetLocation != NSNotFound) if (_dragTargetLocation != NSNotFound)
{ {
_tf.drag_target_hijacks_insertion_point = YES; _tf.drag_target_hijacks_insertion_point = YES;
new = [_layoutManager new = [_layoutManager
insertionPointRectForCharacterIndex: _dragTargetLocation insertionPointRectForCharacterIndex: _dragTargetLocation
inTextContainer: _textContainer]; inTextContainer: _textContainer];
new.origin.x += _textContainerOrigin.x; new.origin.x += _textContainerOrigin.x;
new.origin.y += _textContainerOrigin.y; new.origin.y += _textContainerOrigin.y;
/* If the insertion would extend outside the view (e.g. because it's /* If the insertion would extend outside the view (e.g. because it's
just to the right of a character on the far right edge of the view, just to the right of a character on the far right edge of the view,
a common case for right-aligned text), we force it back in. */ a common case for right-aligned text), we force it back in. */
if (NSMaxX(new) > NSMaxX(_bounds)) if (NSMaxX(new) > NSMaxX(_bounds))
{ {
new.origin.x = NSMaxX(_bounds) - new.size.width; new.origin.x = NSMaxX(_bounds) - new.size.width;
} }
} }
else if (_layoutManager->_selected_range.length > 0 || else if (_layoutManager->_selected_range.length > 0 ||
_layoutManager->_selected_range.location == NSNotFound || _layoutManager->_selected_range.location == NSNotFound ||
!restartFlag) !restartFlag)
{ {
new = NSZeroRect; new = NSZeroRect;
} }
else else
{ {
new = [_layoutManager new = [_layoutManager
insertionPointRectForCharacterIndex: _layoutManager->_selected_range.location insertionPointRectForCharacterIndex: _layoutManager->_selected_range.location
inTextContainer: _textContainer]; inTextContainer: _textContainer];
new.origin.x += _textContainerOrigin.x; new.origin.x += _textContainerOrigin.x;
new.origin.y += _textContainerOrigin.y; new.origin.y += _textContainerOrigin.y;
/* If the insertion would extend outside the view (e.g. because it's /* If the insertion would extend outside the view (e.g. because it's
just to the right of a character on the far right edge of the view, just to the right of a character on the far right edge of the view,
a common case for right-aligned text), we force it back in. */ a common case for right-aligned text), we force it back in. */
if (NSMaxX(new) > NSMaxX(_bounds)) if (NSMaxX(new) > NSMaxX(_bounds))
{ {
new.origin.x = NSMaxX(_bounds) - new.size.width; new.origin.x = NSMaxX(_bounds) - new.size.width;
} }
} }
/* Handle hijacked insertion point (either set above when entering this /* Handle hijacked insertion point (either set above when entering this
method or during the previous call to this method) */ method or during the previous call to this method) */
if (_tf.drag_target_hijacks_insertion_point) if (_tf.drag_target_hijacks_insertion_point)
{ {
// Erase previous insertion point line...
_drawInsertionPointNow = NO; _drawInsertionPointNow = NO;
[self setNeedsDisplayInRect: _insertionPointRect [self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
avoidAdditionalLayout: YES];
// Save new insertion point rectangle...
_insertionPointRect = new; _insertionPointRect = new;
if (_dragTargetLocation != NSNotFound) if (_dragTargetLocation != NSNotFound)
{ {
_insertionPointRect = new; // Draw insertion point line in new location...
_drawInsertionPointNow = YES; _drawInsertionPointNow = YES;
[self setNeedsDisplayInRect: _insertionPointRect [self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
avoidAdditionalLayout: YES]; }
}
else else
_tf.drag_target_hijacks_insertion_point = NO; {
// Drag either completed or cancelled...
_tf.drag_target_hijacks_insertion_point = NO;
}
} }
/* Otherwise, draw insertion point only if there is a need to do so */ /* Otherwise, draw insertion point only if there is a need to do so */
else if ([self shouldDrawInsertionPoint] || _drawInsertionPointNow) else if ([self shouldDrawInsertionPoint] || _drawInsertionPointNow)
{ {
if (restartFlag) if (restartFlag)
{ {
/* Start blinking timer if not yet started */ /* Start blinking timer if not yet started */
if (_insertionPointTimer == nil && [self shouldDrawInsertionPoint]) if (_insertionPointTimer == nil && [self shouldDrawInsertionPoint])
{ {
// NSLog(@"Start timer"); // Save new insertion point rectangle before starting the insertion timer...
_insertionPointRect = new; _insertionPointRect = new;
_insertionPointTimer = [NSTimer scheduledTimerWithTimeInterval: 0.5 [self _startInsertionTimer];
target: self }
selector: @selector(_blink:) else if (_insertionPointTimer != nil)
userInfo: nil {
repeats: YES]; // Erase previous insertion point line...
RETAIN (_insertionPointTimer); if (!NSEqualRects(new, _insertionPointRect))
} {
else if (_insertionPointTimer != nil) _drawInsertionPointNow = NO;
{ [self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
if (!NSEqualRects(new, _insertionPointRect))
{ // Save new insertion point rectangle...
_drawInsertionPointNow = NO; _insertionPointRect = new;
[self setNeedsDisplayInRect: _insertionPointRect }
avoidAdditionalLayout: YES]; }
_insertionPointRect = new;
} /* Ok - blinking has just been turned on. Make sure we start
} * the on/off/on/off blinking from the 'on', because in that way
* the user can see where the insertion point is as soon as
/* Ok - blinking has just been turned on. Make sure we start * possible.
* the on/off/on/off blinking from the 'on', because in that way */
* the user can see where the insertion point is as soon as _drawInsertionPointNow = YES;
* possible. [self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
*/ }
_drawInsertionPointNow = YES;
[self setNeedsDisplayInRect: _insertionPointRect
avoidAdditionalLayout: YES];
}
else if ([self shouldDrawInsertionPoint] && (_insertionPointTimer != nil)) else if ([self shouldDrawInsertionPoint] && (_insertionPointTimer != nil))
{ {
// restartFlag is set to NO when control resigns first responder // restartFlag is set to NO when control resigns first responder
// status or window resings key window status. So we invalidate // status or window resings key window status. So we invalidate
// timer to avoid extra method calls // timer to avoid extra method calls
// NSLog(@"Stop timer"); [self _stopInsertionTimer];
[_insertionPointTimer invalidate];
DESTROY (_insertionPointTimer); // Erase previous insertion point line...
_drawInsertionPointNow = NO;
_drawInsertionPointNow = NO; [self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
[self setNeedsDisplayInRect: _insertionPointRect
avoidAdditionalLayout: YES]; // Save new insertion point rectangle...
_insertionPointRect = new;
_insertionPointRect = new; }
}
[self _updateInputMethodWithInsertionPoint: _insertionPointRect.origin]; [self _updateInputMethodWithInsertionPoint: _insertionPointRect.origin];
} }
} }
@ -4268,16 +4291,16 @@ Figure out how the additional layout stuff is supposed to work.
effectiveRange: &lineFragGlyphRange]; effectiveRange: &lineFragGlyphRange];
if (NSMaxY(lineFragRect) <= NSMaxY(proposedPage)) if (NSMaxY(lineFragRect) <= NSMaxY(proposedPage))
{ {
actualTextBottom = NSMaxY(lineFragRect); actualTextBottom = NSMaxY(lineFragRect);
break; break;
} }
else else
{ {
// We encountered a visible glyph fragment which extents below // We encountered a visible glyph fragment which extents below
// the bottom of the page // the bottom of the page
needsToMoveBottom = YES; needsToMoveBottom = YES;
} }
i = lineFragGlyphRange.location - 1; i = lineFragGlyphRange.location - 1;
} }
@ -5188,23 +5211,23 @@ other than copy/paste or dragging. */
{ {
NSPoint dragPoint; NSPoint dragPoint;
unsigned dragIndex; unsigned dragIndex;
dragPoint = [sender draggingLocation]; dragPoint = [sender draggingLocation];
dragPoint = [self convertPoint: dragPoint fromView: nil]; dragPoint = [self convertPoint: dragPoint fromView: nil];
dragIndex = [self _characterIndexForPoint: dragPoint dragIndex = [self _characterIndexForPoint: dragPoint
respectFraction: YES]; respectFraction: YES];
if ([sender draggingSource] != self || if ([sender draggingSource] != self ||
dragIndex <= [self selectedRange].location || dragIndex <= [self selectedRange].location ||
dragIndex >= NSMaxRange([self selectedRange])) dragIndex >= NSMaxRange([self selectedRange]))
{ {
_dragTargetLocation = dragIndex; _dragTargetLocation = dragIndex;
} }
else else
{ {
_dragTargetLocation = NSNotFound; _dragTargetLocation = NSNotFound;
*flags = NSDragOperationNone; *flags = NSDragOperationNone;
} }
} }
else if (_dragTargetLocation != NSNotFound) else if (_dragTargetLocation != NSNotFound)
{ {
@ -5335,11 +5358,11 @@ other than copy/paste or dragging. */
if ([self readSelectionFromPasteboard: pboard type: type]) if ([self readSelectionFromPasteboard: pboard type: type])
{ {
if (![type isEqual: NSColorPboardType]) if (![type isEqual: NSColorPboardType])
{ {
changeRange.length = changeRange.length =
[self selectedRange].location - changeRange.location; [self selectedRange].location - changeRange.location;
[self setSelectedRange: changeRange]; [self setSelectedRange: changeRange];
} }
return YES; return YES;
} }
return NO; return NO;
@ -5351,7 +5374,10 @@ other than copy/paste or dragging. */
- (void) cleanUpAfterDragOperation - (void) cleanUpAfterDragOperation
{ {
// release drag information // Cleanup information after dragging operation completes...
_dragTargetLocation = NSNotFound;
[self updateInsertionPointStateAndRestartTimer: NO];
[self displayIfNeeded];
} }
- (unsigned int) dragOperationForDraggingInfo: (id <NSDraggingInfo>)dragInfo - (unsigned int) dragOperationForDraggingInfo: (id <NSDraggingInfo>)dragInfo
@ -6034,8 +6060,7 @@ or add guards
_drawInsertionPointNow = YES; _drawInsertionPointNow = YES;
} }
[self setNeedsDisplayInRect: _insertionPointRect [self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
avoidAdditionalLayout: YES];
/* Because we are called by a timer which is independent of any /* Because we are called by a timer which is independent of any
event processing in the gui runloop, we need to manually update event processing in the gui runloop, we need to manually update
the window. */ the window. */

View file

@ -4301,8 +4301,8 @@ resetCursorRectsForView(NSView *theView)
case GSAppKitDraggingDrop: case GSAppKitDraggingDrop:
NSDebugLLog(@"NSDragging", @"GSAppKitDraggingDrop"); NSDebugLLog(@"NSDragging", @"GSAppKitDraggingDrop");
dragInfo = [GSServerForWindow(self) dragInfo]; dragInfo = [GSServerForWindow(self) dragInfo];
if (_lastDragView && _f.accepts_drag if (_lastDragView && _f.accepts_drag &&
&& _lastDragOperationMask != NSDragOperationNone) _lastDragOperationMask != NSDragOperationNone)
{ {
action = YES; action = YES;
GSPerformDragSelector(_lastDragView, GSPerformDragSelector(_lastDragView,
@ -4318,6 +4318,14 @@ resetCursorRectsForView(NSView *theView)
GSPerformVoidDragSelector(_lastDragView, GSPerformVoidDragSelector(_lastDragView,
@selector(concludeDragOperation:), dragInfo); @selector(concludeDragOperation:), dragInfo);
} }
// Check for specific cleanup after drag methods...
if ([_lastDragView respondsToSelector: @selector(cleanUpAfterDragOperation)])
{
GSPerformVoidDragSelector(_lastDragView,
@selector(cleanUpAfterDragOperation),
dragInfo)
}
} }
_lastDragOperationMask = NSDragOperationNone; _lastDragOperationMask = NSDragOperationNone;
DESTROY(_lastDragView); DESTROY(_lastDragView);