Fix a crash during undo/redo when a text storage is shared among

multiple text views and some of these views are closed.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@27360 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Wolfgang Lux 2008-12-19 23:51:25 +00:00
parent e906e7378d
commit 232de18e5e
2 changed files with 86 additions and 18 deletions

View file

@ -1,3 +1,11 @@
2008-12-20 Wolfgang Lux <wolfgang.lux@gmail.com>
* Source/NSTextView.m (-shouldChangeTextInRange:replacementString:):
Fix a crash during undo/redo when a text storage is shared among
multiple text views and some of these views are closed by
recording the undo/redo operations for the text storage rather
than the text view.
2008-12-20 Wolfgang Lux <wolfgang.lux@gmail.com>
* Source/NSApplication.m (-sendEvent:): Attempt to perform key

View file

@ -128,6 +128,14 @@ Interface for a bunch of internal methods that need to be cleaned up.
- (void) pasteSelection;
@end
@interface NSTextStorage(NSTextViewUndoSupport)
- (NSTextView *)_bestTextViewForUndo;
- (void)_undoReplaceCharactersInRange: (NSRange)undoRange
withAttributedString: (NSAttributedString *)undoString
selectedRange: (NSRange)selectedRange;
@end
// This class is a helper for keyed unarchiving only
@interface NSTextViewSharedData : NSObject
{
@ -2388,20 +2396,6 @@ Move to NSTextView_actions.m?
return undo;
}
- (void)undoReplaceCharactersInRange: (NSRange)undoRange
withAttributedString: (NSAttributedString *)undoString
selectedRange: (NSRange)selectedRange
{
if ([self shouldChangeTextInRange: undoRange
replacementString: undoString ? [undoString string] : @""])
{
[self replaceCharactersInRange: undoRange
withAttributedString: undoString];
[self setSelectedRange: selectedRange];
[self didChangeText];
}
}
/*
* Began editing flag. There are quite some different ways in which
* editing can be started. Each time editing is started, we need to check
@ -2504,10 +2498,10 @@ TextDidEndEditing notification _without_ asking the delegate
undoRange = affectedCharRange;
}
undoString = [self attributedSubstringFromRange: affectedCharRange];
[[undo prepareWithInvocationTarget: self]
undoReplaceCharactersInRange: undoRange
withAttributedString: undoString
selectedRange: [self selectedRange]];
[[undo prepareWithInvocationTarget: [self textStorage]]
_undoReplaceCharactersInRange: undoRange
withAttributedString: undoString
selectedRange: [self selectedRange]];
}
return result;
@ -5265,3 +5259,69 @@ configuation! */
@end
@implementation NSTextStorage(NSTextViewUndo)
/* FIXME: Should this code be moved to NSTextStorage? */
- (NSTextView *)_bestTextViewForUndo
{
int i, j;
NSArray *textContainers;
NSTextView *tv, *first = nil, *best = nil;
NSWindow *win;
/* The "best" view will be one in the key window followed by one in the
* main window. In either case, we prefer the window's first responder.
* If no view is in the key or main window, we simply use the first text
* view. Since -shouldChangeTextInRange:replacementString: returns NO
* by default if a NSTextView is not editable, we consider only editable
* views here.
*/
for (i = 0; i < [_layoutManagers count]; i++)
{
textContainers = [[_layoutManagers objectAtIndex: i] textContainers];
for (j = 0; j < [textContainers count]; j++)
{
tv = [[textContainers objectAtIndex: j] textView];
if ([tv isEditable])
{
win = [tv window];
if (first == nil)
first = tv;
if ([win isKeyWindow])
{
if ([win firstResponder] == tv)
return tv;
else if (best == nil)
best = tv;
}
else if ([win isMainWindow])
{
if ([win firstResponder] == tv)
{
if (best == nil || ![[best window] isKeyWindow])
best = tv;
}
else if (best == nil)
best = tv;
}
}
}
}
return best != nil ? best : first;
}
- (void)_undoReplaceCharactersInRange: (NSRange)undoRange
withAttributedString: (NSAttributedString *)undoString
selectedRange: (NSRange)selectedRange
{
NSTextView *tv = [self _bestTextViewForUndo];
if ([tv shouldChangeTextInRange: undoRange
replacementString: undoString ? [undoString string] : @""])
{
[tv replaceCharactersInRange: undoRange
withAttributedString: undoString];
[tv setSelectedRange: selectedRange];
[tv didChangeText];
}
}
@end