diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPCopyTable.h | 56 | ||||
-rw-r--r-- | Source/SPCopyTable.m | 447 | ||||
-rw-r--r-- | Source/SPFieldEditorController.h | 1 | ||||
-rw-r--r-- | Source/SPFieldEditorController.m | 421 |
4 files changed, 475 insertions, 450 deletions
diff --git a/Source/SPCopyTable.h b/Source/SPCopyTable.h index 4ed8dfb7..3ccff43c 100644 --- a/Source/SPCopyTable.h +++ b/Source/SPCopyTable.h @@ -37,13 +37,13 @@ is in similar format. The values for each cell are obtained via the objects description method */ -@interface SPCopyTable : SPTableView +@interface SPCopyTable : SPTableView { - id tableInstance; // the table content view instance - id mySQLConnection; // current MySQL connection - NSArray* columnDefinitions; // array of NSDictionary containing info about columns - NSString* selectedTable; // the name of the current selected table - SPDataStorage* tableStorage; // the underlying storage array holding the table data + id tableInstance; // the table content view instance + id mySQLConnection; // current MySQL connection + NSArray* columnDefinitions; // array of NSDictionary containing info about columns + NSString* selectedTable; // the name of the current selected table + SPDataStorage* tableStorage; // the underlying storage array holding the table data NSUserDefaults *prefs; @@ -51,9 +51,7 @@ } - -- (void)setFieldEditorSelectedRange:(NSRange)aRange; -- (NSRange)fieldEditorSelectedRange; +@property(readwrite,assign) NSRange fieldEditorSelectedRange; /*! @method copy: @@ -65,15 +63,15 @@ - (void)copy:(id)sender; /*! - @method validateMenuItem: - @abstract Dynamically enable Copy menu item for the table view - @discussion Will only enable the Copy item when something is selected in - this table view - @param anItem the menu item being validated - @result YES if there is at least one row selected & the menu item is - copy, NO otherwise + @method draggedRowsAsTabString: + @abstract getter of the dragged rows of the table for drag + @discussion For the dragged rows returns a single string with each row + separated by a newline and then for each column value separated by a + tab. Values are from the objects description method, so make sure it + returns something meaningful. + @result The above described string, or nil if nothing selected */ -- (BOOL)validateMenuItem:(NSMenuItem*)anItem; +- (NSString *)draggedRowsAsTabString; /*! @method draggingSourceOperationMaskForLocal: @@ -94,17 +92,6 @@ */ - (NSString *)selectedRowsAsTabStringWithHeaders:(BOOL)withHeaders; -/*! - @method draggedRowsAsTabString: - @abstract getter of the dragged rows of the table for drag - @discussion For the dragged rows returns a single string with each row - separated by a newline and then for each column value separated by a - tab. Values are from the objects description method, so make sure it - returns something meaningful. - @result The above described string, or nil if nothing selected -*/ -- (NSString *)draggedRowsAsTabString; - /* * Generate a string in form of INSERT INTO <table> VALUES () of * currently selected rows. Support blob data as well. @@ -132,7 +119,7 @@ while this accesses it. @result A dictionary - mapped by column identifier - of the column widths to use */ -- (NSDictionary *) autodetectColumnWidths; +- (NSDictionary *)autodetectColumnWidths; /*! @method autodetectWidthForColumnDefinition:maxRows: @@ -153,6 +140,17 @@ */ - (NSUInteger)autodetectWidthForColumnDefinition:(NSDictionary *)columnDefinition maxRows:(NSUInteger)rowsToCheck; +/*! + @method validateMenuItem: + @abstract Dynamically enable Copy menu item for the table view + @discussion Will only enable the Copy item when something is selected in + this table view + @param anItem the menu item being validated + @result YES if there is at least one row selected & the menu item is + copy, NO otherwise +*/ +- (BOOL)validateMenuItem:(NSMenuItem*)anItem; + - (BOOL)isCellEditingMode; - (BOOL)isCellComplex; diff --git a/Source/SPCopyTable.m b/Source/SPCopyTable.m index 66b97a81..dfb80cc4 100644 --- a/Source/SPCopyTable.m +++ b/Source/SPCopyTable.m @@ -38,51 +38,17 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; @implementation SPCopyTable -- (void)setFieldEditorSelectedRange:(NSRange)aRange -{ - fieldEditorSelectedRange = aRange; -} - -- (NSRange)fieldEditorSelectedRange -{ - return fieldEditorSelectedRange; -} - -- (void)copy:(id)sender -{ - NSString *tmp = nil; - - if([sender tag] == MENU_EDIT_COPY_AS_SQL) { - tmp = [self selectedRowsAsSqlInserts]; - if ( nil != tmp ) - { - NSPasteboard *pb = [NSPasteboard generalPasteboard]; - - [pb declareTypes:[NSArray arrayWithObjects: NSStringPboardType, nil] - owner:nil]; - - [pb setString:tmp forType:NSStringPboardType]; - } - } else { - tmp = [self selectedRowsAsTabStringWithHeaders:([sender tag] == MENU_EDIT_COPY_WITH_COLUMN)]; - if ( nil != tmp ) - { - NSPasteboard *pb = [NSPasteboard generalPasteboard]; - [pb declareTypes:[NSArray arrayWithObjects: NSTabularTextPboardType, - NSStringPboardType, nil] - owner:nil]; - - [pb setString:tmp forType:NSStringPboardType]; - [pb setString:tmp forType:NSTabularTextPboardType]; - } - } -} +/** + * Hold the selected range of the current table cell editor to be able to set this passed + * selection in the field editor's editTextView + */ +@synthesize fieldEditorSelectedRange; -/* +/** * Cell editing in SPCustomQuery or for views in SPTableContent */ -- (BOOL)isCellEditingMode +- (BOOL) isCellEditingMode { return ([[self delegate] isKindOfClass:[SPCustomQuery class]] @@ -92,171 +58,60 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; } -/* +/** * Check if current edited cell represents a class other than a normal NSString * like pop-up menus for enum or set */ -- (BOOL)isCellComplex +- (BOOL) isCellComplex { return (![[self preparedCellAtColumn:[self editedColumn] row:[self editedRow]] isKindOfClass:[SPTextAndLinkCell class]]); } -/* - * Trap the enter, escape, tab and arrow keys, overriding default behaviour and continuing/ending editing, - * only within the current row. +#pragma mark - + +/** + * Handles the general Copy action of selected rows in the table according to sender */ -- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command +- (void) copy:(id)sender { + NSString *tmp = nil; + if([sender tag] == MENU_EDIT_COPY_AS_SQL) { + tmp = [self selectedRowsAsSqlInserts]; + if ( nil != tmp ) + { + NSPasteboard *pb = [NSPasteboard generalPasteboard]; - NSUInteger row, column; - - row = [self editedRow]; - column = [self editedColumn]; - - // Trap tab key - // -- for handling of blob fields and to check if it's editable look at [[self delegate] control:textShouldBeginEditing:] - if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] ) - { - [[control window] makeFirstResponder:control]; + [pb declareTypes:[NSArray arrayWithObjects: NSStringPboardType, nil] + owner:nil]; - // Save the current line if it's the last field in the table - if ( [self numberOfColumns] - 1 == column) { - if([[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - [[self window] makeFirstResponder:self]; - } else { - // Select the next field for editing - [self editColumn:column+1 row:row withEvent:nil select:YES]; + [pb setString:tmp forType:NSStringPboardType]; } + } else { + tmp = [self selectedRowsAsTabStringWithHeaders:([sender tag] == MENU_EDIT_COPY_WITH_COLUMN)]; + if ( nil != tmp ) + { + NSPasteboard *pb = [NSPasteboard generalPasteboard]; - return YES; - } - - // Trap shift-tab key - else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertBacktab:)] ) - { - [[control window] makeFirstResponder:control]; + [pb declareTypes:[NSArray arrayWithObjects: + NSTabularTextPboardType, + NSStringPboardType, + nil] + owner:nil]; - // Save the current line if it's the last field in the table - if ( column < 1 ) { - if([[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - [[self window] makeFirstResponder:self]; - } else { - // Select the previous field for editing - [self editColumn:column-1 row:row withEvent:nil select:YES]; + [pb setString:tmp forType:NSStringPboardType]; + [pb setString:tmp forType:NSTabularTextPboardType]; } - - return YES; - } - - // Trap enter key - else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] ) - { - // If enum field is edited RETURN selects the new value instead of saving the entire row - if([self isCellComplex]) - return YES; - - [[control window] makeFirstResponder:control]; - if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - return YES; - - } - - // Trap down arrow key - else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] ) - { - - // If enum field is edited ARROW key navigates through the popup list - if([self isCellComplex]) - return NO; - - NSUInteger newRow = row+1; - if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check if we're already at the end of the list - - [[control window] makeFirstResponder:control]; - if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - - if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check again. addRowToDB could reload the table and change the number of rows - if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too - - [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; - [self editColumn:column row:newRow withEvent:nil select:YES]; - return YES; } - - // Trap up arrow key - else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] ) - { - - // If enum field is edited ARROW key navigates through the popup list - if([self isCellComplex]) - return NO; - - if (row==0) return YES; //already at the beginning of the list - NSUInteger newRow = row-1; - - [[control window] makeFirstResponder:control]; - if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - - if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; // addRowToDB could reload the table and change the number of rows - if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too - - [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; - [self editColumn:column row:newRow withEvent:nil select:YES]; - return YES; - } - - return NO; -} - - -//allow for drag-n-drop out of the application as a copy -- (NSUInteger)draggingSourceOperationMaskForLocal:(BOOL)isLocal -{ - return NSDragOperationCopy; } /** - * Only have the copy menu item enabled when row(s) are selected in - * supported tables. + * Get selected rows a string of newline separated lines of tab separated fields + * the value in each field is from the objects description method */ -- (BOOL)validateMenuItem:(NSMenuItem*)anItem -{ - NSInteger menuItemTag = [anItem tag]; - - // Don't validate anything other than the copy commands - if (menuItemTag != MENU_EDIT_COPY && menuItemTag != MENU_EDIT_COPY_WITH_COLUMN && menuItemTag != MENU_EDIT_COPY_AS_SQL) { - return YES; - } - - // Don't enable menus for relations or triggers - no action to take yet - if ([[self delegate] isKindOfClass:[SPTableRelations class]] || [[self delegate] isKindOfClass:[SPTableTriggers class]]) { - return NO; - } - - // Enable the Copy [with column names] commands if a row is selected - if (menuItemTag == MENU_EDIT_COPY || menuItemTag == MENU_EDIT_COPY_WITH_COLUMN) { - return ([self numberOfSelectedRows] > 0); - } - - // Enable the Copy as SQL commands if rows are selected and column definitions are available - if (menuItemTag == MENU_EDIT_COPY_AS_SQL) { - return (columnDefinitions != nil && [self numberOfSelectedRows] > 0); - } - - return NO; -} - -//get selected rows a string of newline separated lines of tab separated fields -//the value in each field is from the objects description method -- (NSString *)selectedRowsAsTabStringWithHeaders:(BOOL)withHeaders +- (NSString *) selectedRowsAsTabStringWithHeaders:(BOOL)withHeaders { if ([self numberOfSelectedRows] == 0) return nil; @@ -280,17 +135,18 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; // Create an array of table column mappings for fast iteration NSUInteger *columnMappings = malloc(numColumns * sizeof(NSUInteger)); - for ( c = 0; c < numColumns; c++) { - columnMappings[c] = [[[columns objectAtIndex:c] identifier] unsignedIntValue]; - } + for ( c = 0; c < numColumns; c++ ) + columnMappings[c] = [[NSArrayObjectAtIndex(columns, c) identifier] unsignedIntValue]; // Loop through the rows, adding their descriptive contents NSUInteger rowIndex = [selectedRows firstIndex]; - NSString * nullString = [prefs objectForKey:SPNullValue]; + NSString *nullString = [prefs objectForKey:SPNullValue]; NSStringEncoding connectionEncoding = [mySQLConnection encoding]; + Class mcpGeometryData = [MCPGeometryData class]; + while ( rowIndex != NSNotFound ) { - for ( c = 0; c < numColumns; c++) { + for ( c = 0; c < numColumns; c++ ) { cellData = SPDataStorageObjectAtRowAndColumn(tableStorage, rowIndex, columnMappings[c]); // Copy the shown representation of the cell - custom NULL display strings, (not loaded), @@ -308,9 +164,10 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; [displayString release]; } } - else if ([cellData isKindOfClass:[MCPGeometryData class]]) { + else if ([cellData isKindOfClass:mcpGeometryData]) { [result appendFormat:@"%@\t", [cellData wktString]]; - } else + } + else [result appendFormat:@"%@\t", [cellData description]]; } else { [result appendString:@"\t"]; @@ -341,7 +198,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; * Return selected rows as SQL INSERT INTO `foo` VALUES (baz) string. * If no selected table name is given `<table>` will be used instead. */ -- (NSString *)selectedRowsAsSqlInserts +- (NSString *) selectedRowsAsSqlInserts { if ( [self numberOfSelectedRows] < 1 ) return nil; @@ -371,9 +228,9 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; NSUInteger *columnMappings = malloc(numColumns * sizeof(NSUInteger)); NSUInteger *columnTypes = malloc(numColumns * sizeof(NSUInteger)); for ( c = 0; c < numColumns; c++) { - columnMappings[c] = [[[columns objectAtIndex:c] identifier] unsignedIntValue]; + columnMappings[c] = [[NSArrayObjectAtIndex(columns, c) identifier] unsignedIntValue]; - NSString *t = [[columnDefinitions objectAtIndex:columnMappings[c]] objectForKey:@"typegrouping"]; + NSString *t = [NSArrayObjectAtIndex(columnDefinitions, columnMappings[c]) objectForKey:@"typegrouping"]; // Numeric data if ([t isEqualToString:@"bit"] || [t isEqualToString:@"integer"] || [t isEqualToString:@"float"]) @@ -394,7 +251,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; // Begin the SQL string [result appendFormat:@"INSERT INTO %@ (%@)\nVALUES\n", - [(selectedTable == nil)?@"<table>":selectedTable backtickQuotedString], [tbHeader componentsJoinedAndBacktickQuoted]]; + [(selectedTable == nil) ? @"<table>" : selectedTable backtickQuotedString], [tbHeader componentsJoinedAndBacktickQuoted]]; NSUInteger rowIndex = [selectedRows firstIndex]; Class spTableContentClass = [SPTableContent class]; @@ -485,7 +342,10 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; // Add a new INSERT starter command every ~250k of data. if ( valueLength > 250000 ) { - [result appendFormat:@"%@);\n\nINSERT INTO %@ (%@)\nVALUES\n", value, [(selectedTable == nil)?@"<table>":selectedTable backtickQuotedString], [tbHeader componentsJoinedAndBacktickQuoted]]; + [result appendFormat:@"%@);\n\nINSERT INTO %@ (%@)\nVALUES\n", + value, + [(selectedTable == nil) ? @"<table>" : selectedTable backtickQuotedString], + [tbHeader componentsJoinedAndBacktickQuoted]]; [value setString:@""]; valueLength = 0; } else { @@ -514,10 +374,19 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; return result; } +/** + * Allow for drag-n-drop out of the application as a copy + */ +- (NSUInteger) draggingSourceOperationMaskForLocal:(BOOL)isLocal +{ + return NSDragOperationCopy; +} -//get dragged rows a string of newline separated lines of tab separated fields -//the value in each field is from the objects description method -- (NSString *)draggedRowsAsTabString +/** + * Get dragged rows a string of newline separated lines of tab separated fields + * the value in each field is from the objects description method + */ +- (NSString *) draggedRowsAsTabString { NSArray *columns = [self tableColumns]; NSUInteger numColumns = [columns count]; @@ -529,18 +398,18 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; // Create an array of table column mappings for fast iteration NSUInteger *columnMappings = malloc(numColumns * sizeof(NSUInteger)); - for ( c = 0; c < numColumns; c++) { - columnMappings[c] = [[[columns objectAtIndex:c] identifier] unsignedIntValue]; - } + for ( c = 0; c < numColumns; c++ ) + columnMappings[c] = [[NSArrayObjectAtIndex(columns, c) identifier] unsignedIntValue]; // Loop through the rows, adding their descriptive contents NSUInteger rowIndex = [selectedRows firstIndex]; NSString *nullString = [prefs objectForKey:SPNullValue]; Class nsDataClass = [NSData class]; + Class mcpGeometryData = [MCPGeometryData class]; NSStringEncoding connectionEncoding = [mySQLConnection stringEncoding]; while ( rowIndex != NSNotFound ) { - for ( c = 0; c < numColumns; c++) { + for ( c = 0; c < numColumns; c++ ) { cellData = SPDataStorageObjectAtRowAndColumn(tableStorage, rowIndex, columnMappings[c]); // Copy the shown representation of the cell - custom NULL display strings, (not loaded), @@ -558,7 +427,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; [displayString release]; } } - else if ([cellData isKindOfClass:[MCPGeometryData class]]) { + else if ([cellData isKindOfClass:mcpGeometryData]) { [result appendFormat:@"%@\t", [cellData wktString]]; } else [result appendFormat:@"%@\t", [cellData description]]; @@ -587,28 +456,32 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; return result; } +#pragma mark - + /** * Init self with data coming from the table content view. Mainly used for copying data properly. */ -- (void)setTableInstance:(id)anInstance withTableData:(SPDataStorage *)theTableStorage withColumns:(NSArray *)columnDefs withTableName:(NSString *)aTableName withConnection:(id)aMySqlConnection +- (void) setTableInstance:(id)anInstance withTableData:(SPDataStorage *)theTableStorage withColumns:(NSArray *)columnDefs withTableName:(NSString *)aTableName withConnection:(id)aMySqlConnection { selectedTable = aTableName; mySQLConnection = aMySqlConnection; tableInstance = anInstance; tableStorage = theTableStorage; - if (columnDefinitions) [columnDefinitions release]; + if (columnDefinitions) [columnDefinitions release], columnDefinitions = nil; columnDefinitions = [[NSArray alloc] initWithArray:columnDefs]; } /* * Update the table storage location if necessary. */ -- (void)setTableData:(SPDataStorage *)theTableStorage +- (void) setTableData:(SPDataStorage *)theTableStorage { tableStorage = theTableStorage; } +#pragma mark - + /** * Autodetect column widths for a specified font. */ @@ -670,13 +543,14 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; NSFont *tableFont = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPGlobalResultTableFont]]; NSUInteger columnIndex = [[columnDefinition objectForKey:@"datacolumnindex"] unsignedIntegerValue]; NSDictionary *stringAttributes = [NSDictionary dictionaryWithObject:tableFont forKey:NSFontAttributeName]; + Class mcpGeometryData = [MCPGeometryData class]; // Check the number of rows available to check, sampling every n rows - if ([tableStorage count] < rowsToCheck) { + if ([tableStorage count] < rowsToCheck) rowStep = 1; - } else { + else rowStep = floor([tableStorage count] / rowsToCheck); - } + rowsToCheck = [tableStorage count]; // Set a default padding for this column @@ -690,7 +564,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; contentString = [tableStorage cellDataAtRow:i column:columnIndex]; // Get WKT string out of the MCPGeometryData for calculation - if ([contentString isKindOfClass:[MCPGeometryData class]]) + if ([contentString isKindOfClass:mcpGeometryData]) contentString = [contentString wktString]; // Replace NULLs with their placeholder string @@ -743,7 +617,152 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; return maxCellWidth; } -- (void)keyDown:(NSEvent *)theEvent +#pragma mark - + +/** + * Only have the copy menu item enabled when row(s) are selected in + * supported tables. + */ +- (BOOL) validateMenuItem:(NSMenuItem*)anItem +{ + NSInteger menuItemTag = [anItem tag]; + + // Don't validate anything other than the copy commands + if (menuItemTag != MENU_EDIT_COPY && menuItemTag != MENU_EDIT_COPY_WITH_COLUMN && menuItemTag != MENU_EDIT_COPY_AS_SQL) { + return YES; + } + + // Don't enable menus for relations or triggers - no action to take yet + if ([[self delegate] isKindOfClass:[SPTableRelations class]] || [[self delegate] isKindOfClass:[SPTableTriggers class]]) { + return NO; + } + + // Enable the Copy [with column names] commands if a row is selected + if (menuItemTag == MENU_EDIT_COPY || menuItemTag == MENU_EDIT_COPY_WITH_COLUMN) { + return ([self numberOfSelectedRows] > 0); + } + + // Enable the Copy as SQL commands if rows are selected and column definitions are available + if (menuItemTag == MENU_EDIT_COPY_AS_SQL) { + return (columnDefinitions != nil && [self numberOfSelectedRows] > 0); + } + + return NO; +} + +/** + * Trap the enter, escape, tab and arrow keys, overriding default behaviour and continuing/ending editing, + * only within the current row. + */ +- (BOOL) control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command +{ + + NSUInteger row, column; + + row = [self editedRow]; + column = [self editedColumn]; + + // Trap tab key + // -- for handling of blob fields and to check if it's editable look at [[self delegate] control:textShouldBeginEditing:] + if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] ) + { + [[control window] makeFirstResponder:control]; + + // Save the current line if it's the last field in the table + if ( [self numberOfColumns] - 1 == column ) { + if([[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + [[self window] makeFirstResponder:self]; + } else { + // Select the next field for editing + [self editColumn:column+1 row:row withEvent:nil select:YES]; + } + + return YES; + } + + // Trap shift-tab key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertBacktab:)] ) + { + [[control window] makeFirstResponder:control]; + + // Save the current line if it's the last field in the table + if ( column < 1 ) { + if([[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + [[self window] makeFirstResponder:self]; + } else { + // Select the previous field for editing + [self editColumn:column-1 row:row withEvent:nil select:YES]; + } + + return YES; + } + + // Trap enter key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] ) + { + // If enum field is edited RETURN selects the new value instead of saving the entire row + if([self isCellComplex]) + return YES; + + [[control window] makeFirstResponder:control]; + if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + return YES; + + } + + // Trap down arrow key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] ) + { + + // If enum field is edited ARROW key navigates through the popup list + if([self isCellComplex]) + return NO; + + NSUInteger newRow = row+1; + if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check if we're already at the end of the list + + [[control window] makeFirstResponder:control]; + if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + + if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check again. addRowToDB could reload the table and change the number of rows + if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too + + [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; + [self editColumn:column row:newRow withEvent:nil select:YES]; + return YES; + } + + // Trap up arrow key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] ) + { + + // If enum field is edited ARROW key navigates through the popup list + if([self isCellComplex]) + return NO; + + if (row==0) return YES; //already at the beginning of the list + NSUInteger newRow = row-1; + + [[control window] makeFirstResponder:control]; + if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + + if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; // addRowToDB could reload the table and change the number of rows + if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too + + [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; + [self editColumn:column row:newRow withEvent:nil select:YES]; + return YES; + } + + return NO; +} + +- (void) keyDown:(NSEvent *)theEvent { // RETURN or ENTER invoke editing mode for selected row @@ -776,9 +795,9 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; columnDefinitions = nil; prefs = [[NSUserDefaults standardUserDefaults] retain]; - if ([NSTableView instancesRespondToSelector:@selector(awakeFromNib)]) { - [super awakeFromNib] ; - } + if ([NSTableView instancesRespondToSelector:@selector(awakeFromNib)]) + [super awakeFromNib]; + } - (void) dealloc diff --git a/Source/SPFieldEditorController.h b/Source/SPFieldEditorController.h index 29605c51..625e9869 100644 --- a/Source/SPFieldEditorController.h +++ b/Source/SPFieldEditorController.h @@ -162,6 +162,7 @@ NSInteger editSheetReturnCode; BOOL _isGeometry; NSUndoManager *esUndoManager; + } - (IBAction)closeEditSheet:(id)sender; diff --git a/Source/SPFieldEditorController.m b/Source/SPFieldEditorController.m index a5ec347d..17595947 100644 --- a/Source/SPFieldEditorController.m +++ b/Source/SPFieldEditorController.m @@ -113,14 +113,14 @@ [qlTypesItems addObject:type]; } } - + qlTypes = [[NSDictionary dictionaryWithObject:qlTypesItems forKey:SPQuickLookTypes] retain]; [qlTypesItems release]; fieldType = @""; fieldEncoding = @""; } - + return self; } @@ -144,68 +144,30 @@ [super dealloc]; } -/** - * Set the maximum text length of the underlying table field for input validation. - * - * @param length The maximum text length - */ -- (void)setTextMaxLength:(NSUInteger)length -{ - maxTextLength = length; -} - -/** - * Set the field type of the underlying table field for input validation. - * - * @param aType The field type which will be used for dispatching which sheet will be shown. If type == BIT the bitSheet will be used otherwise the editSheet. - */ -- (void)setFieldType:(NSString*)aType -{ - fieldType = aType; -} - -/** - * Set the field encoding of the underlying table field for displaying it to the user. - * - * @param aEncoding encoding - */ -- (void)setFieldEncoding:(NSString*)aEncoding -{ - fieldEncoding = aEncoding; -} - -/** - * Set if underlying table field allows NULL for several validations. - * - * @param allowNULL If allowNULL is YES NULL value is allowed for the underlying table field - */ -- (void)setAllowNULL:(BOOL)allowNULL -{ - _allowNULL = allowNULL; -} +#pragma mark - /** * Main method for editing data. It will validate several settings and display a modal sheet for theWindow whioch waits until the user closes the sheet. * * @param data The to be edited table field data. - * + * * @param fieldName The name of the currently edited table field. - * + * * @param anEncoding The used encoding while editing. - * + * * @param isFieldBlob If YES the underlying table field is a TEXT/BLOB field. This setting handles several controls which are offered in the sheet to the user. - * + * * @param isEditable If YES the underlying table field is editable, if NO the field is not editable and the SPFieldEditorController sheet do not show a "OK" button for saving. - * + * * @param theWindow The window for displaying the sheet. - * + * * @param sender The calling instance. - * + * * @param contextInfo context info for processing the edited data in sender. - * + * */ - (void)editWithObject:(id)data fieldName:(NSString*)fieldName usingEncoding:(NSStringEncoding)anEncoding - isObjectBlob:(BOOL)isFieldBlob isEditable:(BOOL)isEditable withWindow:(NSWindow *)theWindow + isObjectBlob:(BOOL)isFieldBlob isEditable:(BOOL)isEditable withWindow:(NSWindow *)theWindow sender:(id)sender contextInfo:(NSDictionary*)theContextInfo { @@ -251,10 +213,10 @@ NSInteger i = 0; NSInteger maxBit = (maxTextLength > 64) ? 64 : maxTextLength; if([bitSheetNULLButton state] == NSOffState) - for(i=0; i<maxBit; i++) - [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] + for( i = 0; i<maxBit; i++ ) + [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setState:([sheetEditData characterAtIndex:(maxBit-i-1)] == '1') ? NSOnState : NSOffState]; - for(i=maxBit; i<64; i++) + for( i = maxBit; i<64; i++ ) [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setEnabled:NO]; [self updateBitSheet]; @@ -408,7 +370,6 @@ NSRange selRange = [callerInstance fieldEditorSelectedRange]; [editTextView setSelectedRange:selRange]; [callerInstance setFieldEditorSelectedRange:NSMakeRange(0,0)]; - // If the string content is NULL select NULL for convenience if([stringValue isEqualToString:[prefs objectForKey:SPNullValue]]) @@ -439,71 +400,44 @@ } -- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo +/** + * Set the maximum text length of the underlying table field for input validation. + * + * @param length The maximum text length + */ +- (void)setTextMaxLength:(NSUInteger)length { - // Remember spell cheecker status - [prefs setBool:[editTextView isContinuousSpellCheckingEnabled] forKey:SPBlobTextEditorSpellCheckingEnabled]; + maxTextLength = length; } /** - * Close the editSheet. Before closing it validates the editSheet data against maximum text size. - * If data size is too long select the part which is to long for better editing and keep the sheet opened. - * If any temporary Quicklook files were created delete them before clsoing the sheet. + * Set the field type of the underlying table field for input validation. + * + * @param aType The field type which will be used for dispatching which sheet will be shown. If type == BIT the bitSheet will be used otherwise the editSheet. */ -- (IBAction)closeEditSheet:(id)sender +- (void)setFieldType:(NSString*)aType { + fieldType = aType; +} - editSheetReturnCode = 0; - - // Validate the sheet data before saving them. - // - for max text length (except for NULL value string) select the part which won't be saved - // and suppress closing the sheet - if(sender == editSheetOkButton) { - if (maxTextLength > 0 && [[editTextView textStorage] length] > maxTextLength && ![[[editTextView textStorage] string] isEqualToString:[prefs objectForKey:SPNullValue]]) { - [editTextView setSelectedRange:NSMakeRange(maxTextLength, [[editTextView textStorage] length] - maxTextLength)]; - [editTextView scrollRangeToVisible:NSMakeRange([editTextView selectedRange].location,0)]; - [SPTooltip showWithObject:[NSString stringWithFormat:NSLocalizedString(@"Text is too long. Maximum text length is set to %llu.", @"Text is too long. Maximum text length is set to %llu."), maxTextLength]]; - return; - } - - editSheetReturnCode = 1; - } - else if(sender == bitSheetOkButton && _isEditable) { - editSheetReturnCode = 1; - } - - // Delete all QuickLook temp files if it was invoked - if(tmpFileName != nil) { - NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirPath error:nil]; - for (NSString *file in dirContents) { - if ([file hasPrefix:@"SequelProQuickLook"]) { - if(![[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@", tmpDirPath, file] error:NULL]) { - NSLog(@"QL: Couldn't delete temporary file '%@/%@'.", tmpDirPath, file); - } - } - } - } - - [NSApp endSheet:usedSheet returnCode:1]; - [usedSheet orderOut:self]; - - if(callerInstance) { - id returnData = ( editSheetReturnCode && _isEditable ) ? (_isGeometry) ? [editTextView string] : sheetEditData : nil; - [callerInstance processFieldEditorResult:returnData contextInfo:contextInfo]; - } - +/** + * Set the field encoding of the underlying table field for displaying it to the user. + * + * @param aEncoding encoding + */ +- (void)setFieldEncoding:(NSString*)aEncoding +{ + fieldEncoding = aEncoding; } /** - * Open the open file panel to load a file (text/image) into the editSheet + * Set if underlying table field allows NULL for several validations. + * + * @param allowNULL If allowNULL is YES NULL value is allowed for the underlying table field */ -- (IBAction)openEditSheet:(id)sender +- (void)setAllowNULL:(BOOL)allowNULL { - [[NSOpenPanel openPanel] beginSheetForDirectory:nil - file:@"" - modalForWindow:usedSheet - modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) - contextInfo:NULL]; + _allowNULL = allowNULL; } /** @@ -550,6 +484,18 @@ } /** + * Open the open file panel to load a file (text/image) into the editSheet + */ +- (IBAction)openEditSheet:(id)sender +{ + [[NSOpenPanel openPanel] beginSheetForDirectory:nil + file:@"" + modalForWindow:usedSheet + modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) + contextInfo:NULL]; +} + +/** * Open the save file panel to save the content of the editSheet according to its type as NSData or NSString atomically into the past file. */ - (IBAction)saveEditSheet:(id)sender @@ -575,50 +521,59 @@ contextInfo:NULL]; } +- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo +{ + // Remember spell cheecker status + [prefs setBool:[editTextView isContinuousSpellCheckingEnabled] forKey:SPBlobTextEditorSpellCheckingEnabled]; +} + /** - * Save file panel didEndSelector. If the returnCode == NSOKButton it writes the current content of editSheet according to its type as NSData or NSString atomically into the past file. + * Close the editSheet. Before closing it validates the editSheet data against maximum text size. + * If data size is too long select the part which is to long for better editing and keep the sheet opened. + * If any temporary Quicklook files were created delete them before clsoing the sheet. */ -- (void)savePanelDidEnd:(NSSavePanel *)panel returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo +- (IBAction)closeEditSheet:(id)sender { - if (returnCode == NSOKButton) { - [editSheetProgressBar startAnimation:self]; - - NSString *fileName = [panel filename]; - - // Write binary field types directly to the file - if ( [sheetEditData isKindOfClass:[NSData class]] ) { - [sheetEditData writeToFile:fileName atomically:YES]; + editSheetReturnCode = 0; + // Validate the sheet data before saving them. + // - for max text length (except for NULL value string) select the part which won't be saved + // and suppress closing the sheet + if(sender == editSheetOkButton) { + if (maxTextLength > 0 && [[editTextView textStorage] length] > maxTextLength && ![[[editTextView textStorage] string] isEqualToString:[prefs objectForKey:SPNullValue]]) { + [editTextView setSelectedRange:NSMakeRange(maxTextLength, [[editTextView textStorage] length] - maxTextLength)]; + [editTextView scrollRangeToVisible:NSMakeRange([editTextView selectedRange].location,0)]; + [SPTooltip showWithObject:[NSString stringWithFormat:NSLocalizedString(@"Text is too long. Maximum text length is set to %llu.", @"Text is too long. Maximum text length is set to %llu."), maxTextLength]]; + return; } - else if ( [sheetEditData isKindOfClass:[MCPGeometryData class]] ) { - - if ( [editSheetSegmentControl selectedSegment] == 0 || editImage == nil ) { - - [[editTextView string] writeToFile:fileName - atomically:YES - encoding:encoding - error:NULL]; - } else if (editImage != nil){ - - SPGeometryDataView *v = [[[SPGeometryDataView alloc] initWithCoordinates:[sheetEditData coordinates] targetDimension:2000.0] autorelease]; - NSData *pdf = [v pdfData]; - if(pdf) - [pdf writeToFile:fileName atomically:YES]; + editSheetReturnCode = 1; + } + else if(sender == bitSheetOkButton && _isEditable) { + editSheetReturnCode = 1; + } + // Delete all QuickLook temp files if it was invoked + if(tmpFileName != nil) { + NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirPath error:nil]; + for (NSString *file in dirContents) { + if ([file hasPrefix:@"SequelProQuickLook"]) { + if(![[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@", tmpDirPath, file] error:NULL]) { + NSLog(@"QL: Couldn't delete temporary file '%@/%@'.", tmpDirPath, file); + } } } - // Write other field types' representations to the file via the current encoding - else { - [[sheetEditData description] writeToFile:fileName - atomically:YES - encoding:encoding - error:NULL]; - } + } - [editSheetProgressBar stopAnimation:self]; + [NSApp endSheet:usedSheet returnCode:1]; + [usedSheet orderOut:self]; + + if(callerInstance) { + id returnData = ( editSheetReturnCode && _isEditable ) ? (_isGeometry) ? [editTextView string] : sheetEditData : nil; + [callerInstance processFieldEditorResult:returnData contextInfo:contextInfo]; } + } /** @@ -650,7 +605,6 @@ // set the image preview, string contents and hex representation [editImage setImage:image]; - if(contents) [editTextView setString:contents]; else @@ -687,6 +641,70 @@ } } +/** + * Save file panel didEndSelector. If the returnCode == NSOKButton it writes the current content of editSheet according to its type as NSData or NSString atomically into the past file. + */ +- (void)savePanelDidEnd:(NSSavePanel *)panel returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo +{ + if (returnCode == NSOKButton) { + + [editSheetProgressBar startAnimation:self]; + + NSString *fileName = [panel filename]; + + // Write binary field types directly to the file + if ( [sheetEditData isKindOfClass:[NSData class]] ) { + [sheetEditData writeToFile:fileName atomically:YES]; + + } + else if ( [sheetEditData isKindOfClass:[MCPGeometryData class]] ) { + + if ( [editSheetSegmentControl selectedSegment] == 0 || editImage == nil ) { + + [[editTextView string] writeToFile:fileName + atomically:YES + encoding:encoding + error:NULL]; + + } else if (editImage != nil){ + + SPGeometryDataView *v = [[[SPGeometryDataView alloc] initWithCoordinates:[sheetEditData coordinates] targetDimension:2000.0] autorelease]; + NSData *pdf = [v pdfData]; + if(pdf) + [pdf writeToFile:fileName atomically:YES]; + + } + } + // Write other field types' representations to the file via the current encoding + else { + [[sheetEditData description] writeToFile:fileName + atomically:YES + encoding:encoding + error:NULL]; + } + + [editSheetProgressBar stopAnimation:self]; + } +} + +#pragma mark - +#pragma mark Drop methods + +/** + * If the image was deleted reset all views in editSheet. + * The actual dropped image process is handled by (processUpdatedImageData:). + */ +- (IBAction)dropImage:(id)sender +{ + if ( [editImage image] == nil ) { + if (nil != sheetEditData) [sheetEditData release]; + sheetEditData = [[NSData alloc] init]; + [editTextView setString:@""]; + [hexTextView setString:@""]; + return; + } +} + #pragma mark - #pragma mark QuickLook @@ -703,7 +721,7 @@ /** * Create a temporary file in NSTemporaryDirectory() with the chosen extension type which will be called by Apple's Quicklook generator - * + * * @param type The type as file extension for Apple's default Quicklook generator. * * @param isText If YES the content of editSheet will be treates as pure text. @@ -753,7 +771,7 @@ /** * Opens QuickLook for current data if QuickLook is available - * + * * @param type The type as file extension for Apple's default Quicklook generator. * * @param isText If YES the content of editSheet will be treates as pure text. @@ -842,7 +860,6 @@ } - /** * QuickLook delegate for SDK 10.6. Set the Quicklook delegate to self and suppress setShowsAddToiPhotoButton since the format is unknow. */ @@ -932,9 +949,9 @@ // Return the App's middle point NSRect mwf = [[NSApp mainWindow] frame]; return NSMakeRect( - mwf.origin.x+mwf.size.width/2, - mwf.origin.y+mwf.size.height/2, - 5, 5); + mwf.origin.x+mwf.size.width/2, + mwf.origin.y+mwf.size.height/2, + 5, 5); } // QuickLook delegates for SDK 10.6 @@ -982,7 +999,7 @@ /** * Invoked if the imageView was changed or a file dragged and dropped onto it. - * + * * @param data The image data. If data == nil the reset all views in editSheet. */ - (void)processUpdatedImageData:(NSData *)data @@ -1017,21 +1034,6 @@ editSheetWillBeInitialized = NO; } -/** - * If the image was deleted reset all views in editSheet. - * The actual dropped image process is handled by (processUpdatedImageData:). - */ -- (IBAction)dropImage:(id)sender -{ - if ( [editImage image] == nil ) { - if (nil != sheetEditData) [sheetEditData release]; - sheetEditData = [[NSData alloc] init]; - [editTextView setString:@""]; - [hexTextView setString:@""]; - return; - } -} - #pragma mark - #pragma mark BIT Field Sheet @@ -1043,7 +1045,6 @@ NSInteger i = 0; NSInteger maxBit = (maxTextLength > 64) ? 64 : maxTextLength; - if([bitSheetNULLButton state] == NSOnState) { if ( sheetEditData != nil ) { [sheetEditData release]; @@ -1059,7 +1060,8 @@ NSMutableString *bitString = [NSMutableString string]; [bitString setString:@""]; - for(i=0; i<maxBit; i++) [bitString appendString:@"0"]; + for( i = 0; i<maxBit; i++ ) + [bitString appendString:@"0"]; NSUInteger intValue = 0; NSUInteger bitValue = 0x1; @@ -1096,15 +1098,15 @@ switch([sender tag]) { case 0: // all to 1 - for(i=0; i<maxBit; i++) + for(i=0; i<maxBit; i++) [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setState:NSOnState]; break; case 1: // all to 0 - for(i=0; i<maxBit; i++) + for(i=0; i<maxBit; i++) [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setState:NSOffState]; break; case 2: // negate - for(i=0; i<maxBit; i++) + for(i=0; i<maxBit; i++) [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setState:![[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] state]]; break; case 3: // shift left @@ -1156,13 +1158,13 @@ NSInteger maxBit = (maxTextLength > 64) ? 64 : maxTextLength; if([sender state] == NSOnState) { - for(i=0; i<maxBit; i++) + for(i=0; i<maxBit; i++) [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setEnabled:NO]; [bitSheetHexTextField setEnabled:NO]; [bitSheetIntegerTextField setEnabled:NO]; [bitSheetOctalTextField setEnabled:NO]; } else { - for(i=0; i<maxBit; i++) + for(i=0; i<maxBit; i++) [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setEnabled:YES]; [bitSheetHexTextField setEnabled:YES]; [bitSheetIntegerTextField setEnabled:YES]; @@ -1184,7 +1186,7 @@ } #pragma mark - -#pragma mark Delegates +#pragma mark TextView delegate methods /** * Performs interface validation for various controls. Esp. if user changed the value in bitSheetIntegerTextField or bitSheetHexTextField. @@ -1200,7 +1202,7 @@ NSUInteger intValue = strtoull([[bitSheetIntegerTextField stringValue] UTF8String], NULL, 0); - for(i=0; i<maxBit; i++) + for(i=0; i<maxBit; i++) [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setState:NSOffState]; [bitSheetHexTextField setStringValue:[NSString stringWithFormat:@"%qX", intValue]]; @@ -1224,7 +1226,7 @@ [[NSScanner scannerWithString:[bitSheetHexTextField stringValue]] scanHexLongLong: &intValue]; - for(i=0; i<maxBit; i++) + for(i=0; i<maxBit; i++) [[self valueForKeyPath:[NSString stringWithFormat:@"bitSheetBitButton%ld", i]] setState:NSOffState]; [bitSheetHexTextField setStringValue:[NSString stringWithFormat:@"%qX", intValue]]; @@ -1337,9 +1339,6 @@ } -#pragma - -#pragma TextView delegate methods - /** * Traps enter and return key and closes editSheet instead of inserting a linebreak when user hits return. */ @@ -1357,36 +1356,6 @@ return NO; } -/** - * Establish and return an UndoManager for editTextView - */ -- (NSUndoManager*)undoManagerForTextView:(NSTextView*)aTextView -{ - if (!esUndoManager) - esUndoManager = [[NSUndoManager alloc] init]; - - return esUndoManager; -} - -/** - * Set variable if something in editTextView was cutted or pasted for creating better undo grouping. - */ -- (void)setWasCutPaste -{ - wasCutPaste = YES; -} - - -- (void)setAllowedUndo -{ - allowUndo = YES; -} - -- (void)setDoGroupDueToChars -{ - doGroupDueToChars = YES; -} - /** * Traps any editing in editTextView to allow undo grouping only if the text buffer was really changed. * Inform the run loop delayed for larger undo groups. @@ -1394,8 +1363,8 @@ - (void)textDidChange:(NSNotification *)aNotification { - [NSObject cancelPreviousPerformRequestsWithTarget:self - selector:@selector(setAllowedUndo) + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(setAllowedUndo) object:nil]; // If conditions match create an undo group @@ -1421,4 +1390,42 @@ } +#pragma mark - +#pragma mark UndoManager methods + +/** + * Establish and return an UndoManager for editTextView + */ +- (NSUndoManager*)undoManagerForTextView:(NSTextView*)aTextView +{ + if (!esUndoManager) + esUndoManager = [[NSUndoManager alloc] init]; + + return esUndoManager; +} + +/** + * Set variable if something in editTextView was cutted or pasted for creating better undo grouping. + */ +- (void)setWasCutPaste +{ + wasCutPaste = YES; +} + +/** + * Will be invoke delayed for creating better undo grouping according to type speed (see [self textDidChange:]). + */ +- (void)setAllowedUndo +{ + allowUndo = YES; +} + +/** + * Will be set if according to characters typed in editTextView for creating better undo grouping. + */ +- (void)setDoGroupDueToChars +{ + doGroupDueToChars = YES; +} + @end |