diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPEditSheetTextView.h | 3 | ||||
-rw-r--r-- | Source/SPEditSheetTextView.m | 46 | ||||
-rw-r--r-- | Source/SPFieldEditorController.h | 3 | ||||
-rw-r--r-- | Source/SPFieldEditorController.m | 61 |
4 files changed, 105 insertions, 8 deletions
diff --git a/Source/SPEditSheetTextView.h b/Source/SPEditSheetTextView.h index 7c225a78..d6af35ce 100644 --- a/Source/SPEditSheetTextView.h +++ b/Source/SPEditSheetTextView.h @@ -25,6 +25,9 @@ #import <Cocoa/Cocoa.h> @interface SPEditSheetTextView : NSTextView +{ + BOOL textWasChanged; +} - (unsigned int)characterIndexOfPoint:(NSPoint)aPoint; - (void)insertFileContentOfFile:(NSString *)aPath; diff --git a/Source/SPEditSheetTextView.m b/Source/SPEditSheetTextView.m index 83b691c9..bcde1167 100644 --- a/Source/SPEditSheetTextView.m +++ b/Source/SPEditSheetTextView.m @@ -28,7 +28,47 @@ @implementation SPEditSheetTextView -- (void) keyDown:(NSEvent *)theEvent +- (IBAction)undo:(id)sender +{ + textWasChanged = NO; + [[self undoManager] undo]; + // Due to the undoManager implementation it could happen that + // an action will be recoreded which actually didn't change the + // text buffer. That's why repeat undo. + if(!textWasChanged) [[self undoManager] undo]; +} + +- (IBAction)redo:(id)sender +{ + textWasChanged = NO; + [[self undoManager] redo]; + // Due to the undoManager implementation it could happen that + // an action will be recoreded which actually didn't change the + // text buffer. That's why repeat redo. + if(!textWasChanged) [[self undoManager] redo]; +} + +/* + * Validate undo and redo menu items + */ +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem +{ + + if ([menuItem action] == @selector(undo:)) { + return ([[self undoManager] canUndo]); + } + if ([menuItem action] == @selector(redo:)) { + return ([[self undoManager] canRedo]); + } + return YES; +} + +- (void)textDidChange:(NSNotification *)aNotification +{ + textWasChanged = YES; +} + +- (void)keyDown:(NSEvent *)theEvent { long allFlags = (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask); @@ -62,9 +102,9 @@ return; } } - + [super keyDown: theEvent]; - + } /* diff --git a/Source/SPFieldEditorController.h b/Source/SPFieldEditorController.h index a330108e..e5fbb0e3 100644 --- a/Source/SPFieldEditorController.h +++ b/Source/SPFieldEditorController.h @@ -51,10 +51,13 @@ int counter; unsigned long long maxTextLength; BOOL editTextViewWasChanged; + BOOL allowUndo; NSUserDefaults *prefs; int editSheetReturnCode; + + NSUndoManager *esUndoManager; } - (IBAction)closeEditSheet:(id)sender; diff --git a/Source/SPFieldEditorController.m b/Source/SPFieldEditorController.m index 739e5b08..b2193b32 100644 --- a/Source/SPFieldEditorController.m +++ b/Source/SPFieldEditorController.m @@ -51,7 +51,7 @@ // Allow the user to enter cmd+return to close the edit sheet in addition to fn+return [editSheetOkButton setKeyEquivalentModifierMask:NSCommandKeyMask]; - // [editTextView setFormatter:[[SPDataCellFormatter new] autorelease]]; + allowUndo = NO; } return self; @@ -60,6 +60,7 @@ - (void)dealloc { + if ( esUndoManager ) [esUndoManager release]; if ( sheetEditData ) [sheetEditData release]; [super dealloc]; } @@ -209,11 +210,43 @@ // wait for editSheet NSModalSession session = [NSApp beginModalSessionForWindow:editSheet]; - int response; + int cycleCounter = 0; for (;;) { - if (response = [NSApp runModalSession:session] != NSRunContinuesResponse + + cycleCounter++; + + // Allow undo grouping if user typed a ' ' (for word level undo) + // or a RETURN + if([[NSApp currentEvent] type] == NSKeyDown + && ( + [[[NSApp currentEvent] charactersIgnoringModifiers] isEqualToString:@" "] + || [[NSApp currentEvent] keyCode] == 36 + ) + ) + cycleCounter=100; + + // After 5 run loops (fast writing forms longer blocks) + // or the user typed a ' ' or RETURN and the textView was changed (allowUndo) + // form an undo group + if(cycleCounter>5 && allowUndo && ![esUndoManager isUndoing] && ![esUndoManager isRedoing]) { + cycleCounter=0; + allowUndo = NO; + while([esUndoManager groupingLevel] > 0) { + [esUndoManager endUndoGrouping]; + cycleCounter++; + } + while([esUndoManager groupingLevel] < cycleCounter) + [esUndoManager beginUndoGrouping]; + + cycleCounter = 0; + } + + // Break the run loop if editSheet was closed + if ([NSApp runModalSession:session] != NSRunContinuesResponse || ![editSheet isVisible]) break; + + // Execute code on DefaultRunLoop (like displaying a tooltip) [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; @@ -228,6 +261,17 @@ return ( editSheetReturnCode && isEditable ) ? [sheetEditData retain] : nil; } +/* + * Establish and return an UndoManager for editTextView + */ +- (NSUndoManager*)undoManagerForTextView:(NSTextView*)aTextView +{ + if (!esUndoManager) + esUndoManager = [[NSUndoManager alloc] init]; + + return esUndoManager; +} + - (IBAction)closeEditSheet:(id)sender { @@ -235,6 +279,7 @@ // Validate the sheet data before saving them. // - for max text length select the part which won't be saved + // and suppress closing the sheet if(sender == editSheetOkButton) { if (maxTextLength > 0 && [[editTextView textStorage] length] > maxTextLength) { [editTextView setSelectedRange:NSMakeRange(maxTextLength, [[editTextView textStorage] length] - maxTextLength)]; @@ -741,9 +786,8 @@ if ( [aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)] && [[[NSApp currentEvent] characters] isEqualToString:@"\003"] ) { - // [NSApp stopModalWithCode:1]; - // return YES; [self closeEditSheet:editSheetOkButton]; + return YES; } else return NO; @@ -751,5 +795,12 @@ return NO; } +- (void)textDidChange:(NSNotification *)aNotification +{ + // Allow undo grouping only if the text buffer was really changed + allowUndo = YES; +} + + @end |