This commit is contained in:
Nicholas Shanks 2002-11-15 15:12:42 +00:00
parent 9747396b40
commit 67d2e62f18
15 changed files with 297 additions and 34 deletions

View File

@ -17,3 +17,10 @@ int compareResourcesAscending( Resource *r1, Resource *r2, void *context );
int compareResourcesDescending( Resource *r1, Resource *r2, void *context );
@end
@interface NSOutlineView (OutlineSortView)
- (void)swapForOutlineSortView;
@end
@interface OutlineSortView : NSOutlineView
@end

View File

@ -8,16 +8,20 @@
- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn
{
NSArray *oldResources = [(ResourceDataSource *)[tableView dataSource] resources];
NSArray *newResources;
NSLog( @"Clicked table column: %@", tableColumn );
NSArray *oldResources = [(ResourceDataSource *)[tableView dataSource] resources];
// sort the array
if( ![[tableView indicatorImageInTableColumn:tableColumn] isFlipped] )
NSImage *indicator = [tableView indicatorImageInTableColumn:tableColumn];
NSImage *upArrow = [NSTableView _defaultTableHeaderSortImage];
if( indicator == upArrow )
{
newResources = [oldResources sortedArrayUsingFunction:compareResourcesAscending context:(void*)[tableColumn identifier]];
}
else
{
newResources = [oldResources sortedArrayUsingFunction:compareResourcesDescending context:(void*)[tableColumn identifier]];
}
// swap new array for old one
[(ResourceDataSource *)[tableView dataSource] setResources:[NSMutableArray arrayWithArray:newResources]];
@ -30,9 +34,15 @@ int compareResourcesAscending( Resource *r1, Resource *r2, void *context )
SEL sel = NSSelectorFromString(key);
if( [key isEqualToString:@"name"] || [key isEqualToString:@"type"] )
{
// compare two NSStrings (case-insensitive)
return [(NSString *)[r1 performSelector:sel] caseInsensitiveCompare: (NSString *)[r2 performSelector:sel]];
}
else
{
// compare two NSNumbers (or any other class)
return [(NSNumber *)[r1 performSelector:sel] compare: (NSNumber *)[r2 performSelector:sel]];
}
}
int compareResourcesDescending( Resource *r1, Resource *r2, void *context )
@ -41,9 +51,15 @@ int compareResourcesDescending( Resource *r1, Resource *r2, void *context )
SEL sel = NSSelectorFromString(key);
if( [key isEqualToString:@"name"] || [key isEqualToString:@"type"] )
{
// compare two NSStrings (case-insensitive)
return -1 * [(NSString *)[r1 performSelector:sel] caseInsensitiveCompare: (NSString *)[r2 performSelector:sel]];
}
else
{
// compare two NSNumbers (or any other class)
return -1 * [(NSNumber *)[r1 performSelector:sel] compare: (NSNumber *)[r2 performSelector:sel]];
}
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
@ -79,4 +95,109 @@ int compareResourcesDescending( Resource *r1, Resource *r2, void *context )
}
}
@end
@implementation NSOutlineView (OutlineSortView)
- (void)swapForOutlineSortView
{
isa = [OutlineSortView class];
}
@end
@implementation OutlineSortView
- (void)keyDown:(NSEvent *)event
{
if( [self selectedRow] != -1 && [[event characters] isEqualToString:[NSString stringWithCString:"\r"]] )
[self editColumn:0 row:[self selectedRow] withEvent:nil select:YES];
else [super keyDown:event];
}
- (BOOL)textView:(NSTextView *)textView doCommandBySelector:(SEL)selector
{
// pressed return, end editing
if( selector == @selector(insertNewline:) )
{
[[self window] makeFirstResponder:self];
[self abortEditing];
return YES;
}
// pressed tab, move to next editable field
else if( selector == @selector(insertTab:) )
{
int newColumn = ([self editedColumn] +1) % [self numberOfColumns];
NSString *newColIdentifier = [[[self tableColumns] objectAtIndex:newColumn] identifier];
if( [newColIdentifier isEqualToString:@"size"] || [newColIdentifier isEqualToString:@"attributes"] )
{
newColumn = (newColumn +1) % [self numberOfColumns];
newColIdentifier = [[[self tableColumns] objectAtIndex:newColumn] identifier];
if( [newColIdentifier isEqualToString:@"size"] || [newColIdentifier isEqualToString:@"attributes"] )
newColumn = (newColumn +1) % [self numberOfColumns];
}
[self editColumn:newColumn row:[self selectedRow] withEvent:nil select:YES];
return YES;
}
// pressed shift-tab, move to previous editable field
else if( selector == @selector(insertBacktab:) )
{
int newColumn = ([self editedColumn] + [self numberOfColumns] -1) % [self numberOfColumns];
NSString *newColIdentifier = [[[self tableColumns] objectAtIndex:newColumn] identifier];
if( [newColIdentifier isEqualToString:@"size"] || [newColIdentifier isEqualToString:@"attributes"] )
{
newColumn = (newColumn + [self numberOfColumns] -1) % [self numberOfColumns];
newColIdentifier = [[[self tableColumns] objectAtIndex:newColumn] identifier];
if( [newColIdentifier isEqualToString:@"size"] || [newColIdentifier isEqualToString:@"attributes"] )
newColumn = (newColumn + [self numberOfColumns] -1) % [self numberOfColumns];
}
[self editColumn:newColumn row:[self selectedRow] withEvent:nil select:YES];
return YES;
}
return NO;
}
//- (void)_sendDelegateDidMouseDownInHeader:(int)columnIndex
- (void)_sendDelegateDidClickColumn:(int)columnIndex
{
NSTableColumn *tableColumn = [[self tableColumns] objectAtIndex:columnIndex];
NSImage *indicator = [self indicatorImageInTableColumn:tableColumn];
NSImage *upArrow = [NSTableView _defaultTableHeaderSortImage];
NSImage *downArrow = [NSTableView _defaultTableHeaderReverseSortImage];
if( indicator )
{
// column already selected
if( indicator == upArrow )
[self setIndicatorImage:downArrow inTableColumn:tableColumn];
else [self setIndicatorImage:upArrow inTableColumn:tableColumn];
}
else
{
// new column selected
if( [self highlightedTableColumn] != nil )
{
// if there is an existing selection, clear it's image
[self setIndicatorImage:nil inTableColumn:[self highlightedTableColumn]];
}
if( [[tableColumn identifier] isEqualToString:@"name"] || [[tableColumn identifier] isEqualToString:@"type"] )
{
// sort name and type columns ascending by default
[self setIndicatorImage:upArrow inTableColumn:tableColumn];
}
else
{
// sort all other columns descending by default
[self setIndicatorImage:downArrow inTableColumn:tableColumn];
}
[self setHighlightedTableColumn:tableColumn];
}
[[self delegate] tableView:self didClickTableColumn:tableColumn];
}
@end

View File

@ -109,7 +109,9 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
{
#pragma unused( outlineView )
NSString *identifier = [tableColumn identifier];
[item takeValue:object forKey:identifier];
if( [identifier isEqualToString:@"resID"] )
[item takeValue:[NSNumber numberWithInt:[object intValue]] forKey:identifier];
else [item takeValue:object forKey:identifier];
}
/* ACCESSORS */

View File

@ -4,6 +4,7 @@
#import "Resource.h"
#import "PrefsWindowController.h"
#import "CreateResourceSheetController.h"
#import "OutlineViewDelegate.h"
#import "NSOutlineView-SelectedItems.h"
#import "ResKnifePluginProtocol.h"
@ -62,6 +63,9 @@ extern NSString *RKResourcePboardType;
// set outline view's inter-cell psacing to zero to avoid getting gaps between blue bits
[outlineView setIntercellSpacing:NSMakeSize(0,0)];
[outlineView swapForOutlineSortView];
[outlineView setTarget:self];
[outlineView setDoubleAction:@selector(openResources:)];
// register for resource will change notifications (for undo management)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceNameWillChange:) name:ResourceNameWillChangeNotification object:nil];

View File

@ -124,7 +124,7 @@
// get the superclass to draw the text stuff
[super drawWithFrame:cellFrame inView:controlView];
}
/*
- (NSSize)cellSize
{
NSSize cellSize = [super cellSize];
@ -132,5 +132,5 @@
cellSize.width += (image? [image size].width:0) + 3;
return cellSize;
}
*/
@end

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>306 119 486 325 0 0 1280 1002 </string>
<string>75 336 486 325 0 0 1024 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<string>286.0</string>
<key>IBSystem Version</key>
<string>5Q45</string>
<string>6C115</string>
<key>IBUserGuides</key>
<dict>
<key>CreateResourceSheet</key>

View File

@ -14,12 +14,15 @@
SUPERCLASS = NSObject;
},
{
ACTIONS = {showFind = id; };
CLASS = HexWindowController;
LANGUAGE = ObjC;
OUTLETS = {
ascii = NSTextView;
asciiScroll = NSScrollView;
hex = NSTextView;
hexDelegate = HexEditorDelegate;
hexScroll = NSScrollView;
message = NSTextField;
offset = NSTextView;
};

View File

@ -1,12 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>539 135 422 584 0 0 1280 1002 </string>
<string>137 230 413 304 0 0 1024 746 </string>
<key>IBFramework Version</key>
<string>263.2</string>
<string>286.0</string>
<key>IBOpenObjects</key>
<array>
<integer>6</integer>
</array>
<key>IBSystem Version</key>
<string>5Q125</string>
<string>6C115</string>
</dict>
</plist>

View File

@ -116,6 +116,23 @@
return representation;
}
- (NSString *)hexToAscii:(NSData *)data;
{
unsigned long bytesEncoded = ([data length] + 1) / 3;
char *buffer = (char *) malloc( bytesEncoded ), hex1, hex2, ascii;
for( int i = 0; i < bytesEncoded; i++ )
{
hex1 = ((char *)[data bytes])[3*i];
hex2 = ((char *)[data bytes])[3*i+1];
hex1 -= (hex1 < 'A')? 0x30 : 0x37;
hex2 -= (hex2 < 'A')? 0x30 : 0x37;
hex1 <<= 4;
ascii = hex1 + hex2;
buffer[i] = ascii;
}
return [NSString stringWithCString:buffer length:bytesEncoded];
}
/* delegation methods */
- (NSRange)textView:(NSTextView *)textView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange

View File

@ -5,9 +5,9 @@
@interface HexTextView : NSTextView
{
}
- (void)pasteAsASCII:(id)sender;
- (void)pasteAsHex:(id)sender;
- (void)pasteAsUnicode:(id)sender;
- (IBAction)pasteAsASCII:(id)sender;
- (IBAction)pasteAsHex:(id)sender;
- (IBAction)pasteAsUnicode:(id)sender;
- (void)editData:(NSData *)data replaceBytesInRange:(NSRange)range withData:(NSData *)newData;
@end

View File

@ -76,8 +76,6 @@
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
// NSMenuItem *pasteItem = [[item menu] itemAtIndex:[[item menu] indexOfItemWithTarget:nil andAction:@selector(paste:)]];
// paste submenu
if( [item action] == @selector(paste:) )
{
@ -87,7 +85,33 @@
else return [super validateMenuItem:item];
}
- (void)paste:(id)sender
- (IBAction)cut:(id)sender
{
[self copy:sender];
[self clear:sender];
}
- (IBAction)copy:(id)sender
{
NSRange selection = [self rangeForUserTextChange], byteSelection;
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
// get selection range
if( self == (id) [[self delegate] hex] )
byteSelection = [[self delegate] byteRangeFromHexRange:selection];
else if( self == (id) [[self delegate] ascii] )
byteSelection = [[self delegate] byteRangeFromAsciiRange:selection];
else
{
NSLog( @"Pasting text into illegal object: %@", self );
return;
}
[pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
[pb setData:[[[[self window] windowController] data] subdataWithRange:byteSelection] forType:NSStringPboardType];
}
- (IBAction)paste:(id)sender
{
// be 'smart' - determine if the pasted text is in hex format, such as "5F 3E 04 8E" or ascii.
// what about unicode? should I paste "00 63 00 64" as "63 64" ("Paste As ASCII" submenu item)?
@ -110,7 +134,7 @@
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:[pb dataForType:NSStringPboardType]];
}
- (void)pasteAsASCII:(id)sender
- (IBAction)pasteAsASCII:(id)sender
{
NSRange selection = [self rangeForUserTextChange], byteSelection;
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
@ -130,7 +154,7 @@
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:[pb dataForType:NSStringPboardType]];
}
- (void)pasteAsHex:(id)sender
- (IBAction)pasteAsHex:(id)sender
{
NSRange selection = [self rangeForUserTextChange], byteSelection;
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
@ -153,7 +177,7 @@
}
}
- (void)pasteAsUnicode:(id)sender
- (IBAction)pasteAsUnicode:(id)sender
{
NSRange selection = [self rangeForUserTextChange], byteSelection;
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
@ -171,23 +195,85 @@
if( [pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]] )
{
NSData *unicodeData = [[pb stringForType:NSStringPboardType] dataUsingEncoding:NSUnicodeStringEncoding];
NSData *unicodeData = [[NSString stringWithUTF8String:[[pb dataForType:NSStringPboardType] bytes]] dataUsingEncoding:NSUnicodeStringEncoding];
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:unicodeData];
}
}
- (void)clear:(id)sender
- (IBAction)clear:(id)sender
{
NSRange selection = [self rangeForUserTextChange];
if( selection.length > 0 )
[self delete:sender];
}
- (void)delete:(id)sender
- (IBAction)delete:(id)sender
{
[self deleteBackward:sender];
}
/* Dragging routines */
- (unsigned int)_insertionGlyphIndexForDrag:(id <NSDraggingInfo>)sender
{
int charIndex = [super _insertionGlyphIndexForDrag:sender];
if( self == [[self delegate] hex] )
charIndex -= charIndex % 3;
return charIndex;
}
- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)isLocal
{
return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric;
}
static NSRange draggedRange;
- (void)draggedImage:(NSImage *)image beganAt:(NSPoint)point
{
draggedRange = [self rangeForUserTextChange];
}
- (void)draggedImage:(NSImage *)image endedAt:(NSPoint)point operation:(NSDragOperation)operation
{
if( operation == NSDragOperationMove )
{
NSRange selection = [self rangeForUserTextChange];
[self editData:[[[self window] windowController] data] replaceBytesInRange:draggedRange withData:[NSData data]];
// set the new selection/insertion point
if( selection.location > draggedRange.location )
selection.location -= draggedRange.length;
[self setSelectedRange:selection];
}
}
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
{
[super draggingUpdated:sender]; // ignore return value
if( [sender draggingSource] == [[self delegate] hex] || [sender draggingSource] == [[self delegate] ascii] )
return NSDragOperationMove;
else return NSDragOperationCopy;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSRange range;
NSPasteboard *pb = [sender draggingPasteboard];
NSData *pastedData = [pb dataForType:NSStringPboardType];
int charIndex = [self _insertionGlyphIndexForDrag:sender];
if( self == [[self delegate] hex] ) charIndex /= 3;
if( [sender draggingSource] == [[self delegate] hex] )
pastedData = [[[self delegate] hexToAscii:pastedData] dataUsingEncoding:NSASCIIStringEncoding];
[self editData:[[[self window] windowController] data] replaceBytesInRange:NSMakeRange(charIndex,0) withData:pastedData];
return YES;
}
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
// override and do nothing
}
/* NSResponder overrides */
- (void)insertText:(NSString *)string

View File

@ -5,14 +5,19 @@
#import "ResKnifePluginProtocol.h"
#import "ResKnifeResourceProtocol.h"
#define kWindowStepWidthPerChar 28
#define kWindowStepCharsPerStep 1
@interface HexWindowController : NSWindowController <ResKnifePluginProtocol>
{
IBOutlet HexEditorDelegate *hexDelegate;
IBOutlet NSTextView *ascii;
IBOutlet NSTextView *hex;
IBOutlet NSTextView *offset;
IBOutlet NSTextField *message;
IBOutlet NSMenu *pasteSubmenu;
IBOutlet NSScrollView *asciiScroll;
IBOutlet NSScrollView *hexScroll;
IBOutlet NSTextView *ascii;
IBOutlet NSTextView *hex;
IBOutlet NSTextView *offset;
IBOutlet NSTextField *message;
IBOutlet NSMenu *pasteSubmenu;
NSUndoManager *undoManager;
id <ResKnifeResourceProtocol> resource;

View File

@ -53,6 +53,8 @@
// insert the resources' data into the text fields
[self refreshData:[resource data]];
[[self window] setResizeIncrements:NSMakeSize(kWindowStepWidthPerChar * kWindowStepCharsPerStep, 1)];
// min 346, step 224, norm 570, step 224, max 794
// we don't want this notification until we have a window! (Only register for notifications on the resource we're editing)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceNameDidChange:) name:ResourceNameDidChangeNotification object:resource];
@ -67,6 +69,18 @@
[self showWindow:self];
}
- (void)windowDidResize:(NSNotification *)notification
{
int width = [[notification object] frame].size.width;
int oldBytesPerRow = bytesPerRow;
bytesPerRow = (((width - (kWindowStepWidthPerChar * kWindowStepCharsPerStep) - 122) / (kWindowStepWidthPerChar * kWindowStepCharsPerStep)) + 1) * kWindowStepCharsPerStep;
if( bytesPerRow != oldBytesPerRow )
[offset setString:[hexDelegate offsetRepresentation:[resource data]]];
[hexScroll setFrameSize:NSMakeSize( (bytesPerRow * 21) + 5, [hexScroll frame].size.height)];
[asciiScroll setFrameOrigin:NSMakePoint( (bytesPerRow * 21) + 95, 20)];
[asciiScroll setFrameSize:NSMakeSize( (bytesPerRow * 7) + 28, [asciiScroll frame].size.height)];
}
- (void)windowDidBecomeKey:(NSNotification *)notification
{
// swap paste: menu item for my own paste submenu