Changes accumulated on my G5 while repository was inaccessible.
@ -10,7 +10,7 @@
|
||||
else return [self itemAtRow:[self selectedRow]];
|
||||
}
|
||||
|
||||
- (NSArray *)selectedItems;
|
||||
- (NSArray *)selectedItems
|
||||
{
|
||||
NSNumber *row;
|
||||
NSMutableArray *items = [NSMutableArray array];
|
||||
|
@ -6,3 +6,11 @@
|
||||
- (FSSpec *)createFSSpec;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface NSString (ResKnifeBooleanExtensions)
|
||||
|
||||
- (BOOL)boolValue;
|
||||
+ (NSString *)stringWithBool:(BOOL)boolean;
|
||||
|
||||
@end
|
@ -4,7 +4,8 @@
|
||||
|
||||
- (FSRef *)createFSRef
|
||||
{
|
||||
FSRef *fsRef = NULL;
|
||||
// caller is responsible for disposing of the FSRef (method is a 'create' method)
|
||||
FSRef *fsRef = (FSRef *) NewPtrClear(sizeof(FSRef));
|
||||
OSStatus error = FSPathMakeRef([self fileSystemRepresentation], fsRef, NULL);
|
||||
if(error == noErr)
|
||||
return fsRef;
|
||||
@ -13,16 +14,36 @@
|
||||
|
||||
- (FSSpec *)createFSSpec
|
||||
{
|
||||
FSRef *fsRef = NULL;
|
||||
FSSpec *fsSpec = NULL;
|
||||
// caller is responsible for disposing of the FSSpec (method is a 'create' method)
|
||||
FSRef *fsRef = (FSRef *) NewPtrClear(sizeof(FSRef));
|
||||
FSSpec *fsSpec = (FSSpec *) NewPtrClear(sizeof(FSSpec));
|
||||
OSStatus error = FSPathMakeRef([self fileSystemRepresentation], fsRef, NULL);
|
||||
if(error == noErr)
|
||||
{
|
||||
error = FSGetCatalogInfo(fsRef, kFSCatInfoNone, NULL, NULL, fsSpec, NULL);
|
||||
if(error == noErr)
|
||||
{
|
||||
DisposePtr((Ptr) fsRef);
|
||||
return fsSpec;
|
||||
}
|
||||
}
|
||||
DisposePtr((Ptr) fsRef);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSString (ResKnifeBooleanExtensions)
|
||||
|
||||
- (BOOL)boolValue
|
||||
{
|
||||
return ![self isEqualToString:@"NO"];
|
||||
// return [self isEqualToString:@"YES"];
|
||||
}
|
||||
|
||||
+ (NSString *)stringWithBool:(BOOL)boolean
|
||||
{
|
||||
return boolean? @"YES" : @"NO";
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -1,75 +1,100 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/*! @header ApplicationDelegate.h
|
||||
* @discussion This class is the delegate object for NSApp.
|
||||
/*!
|
||||
@header ApplicationDelegate.h
|
||||
@abstract This class is the delegate object for NSApp.
|
||||
*/
|
||||
|
||||
/*! @class ApplicationDelegate
|
||||
* @discussion This class is the delegate object for NSApp.
|
||||
/*!
|
||||
@class ApplicationDelegate
|
||||
@abstract This class is the delegate object for NSApp.
|
||||
*/
|
||||
@class OpenPanelDelegate;
|
||||
|
||||
@interface ApplicationDelegate : NSObject
|
||||
{
|
||||
/*! @var openAuxView Accessory view for <tt>NSOpenPanels</tt>. */
|
||||
IBOutlet NSView *openAuxView;
|
||||
/*! @var forkTableView Table view inside <tt>openAuxView</tt>. */
|
||||
IBOutlet NSTableView *forkTableView;
|
||||
/*! @var openPanelDelegate Delegate for <tt>NSOpenPanels</tt>. */
|
||||
IBOutlet OpenPanelDelegate *openPanelDelegate;
|
||||
/*! @var icons A dictionary within which to cache icons. Keys are four-character <tt>NSStrings</tt> representing <tt>ResTypes</tt>. */
|
||||
NSMutableDictionary *icons;
|
||||
NSMutableDictionary *_icons;
|
||||
}
|
||||
|
||||
/*! @function showAbout:
|
||||
* @discussion Displays the about box located in <b>AboutPanel.nib</b>.
|
||||
/*!
|
||||
@method showAbout:
|
||||
@abstract Displays the about box located in <b>AboutPanel.nib</b>.
|
||||
*/
|
||||
- (IBAction)showAbout:(id)sender;
|
||||
|
||||
/*! @function visitWebsite:
|
||||
* @discussion Takes the user to <i>http://web.nickshanks.com/resknife/</i>.
|
||||
/*!
|
||||
@method visitWebsite:
|
||||
@abstract Takes the user to <i>http://web.nickshanks.com/resknife/</i>.
|
||||
*/
|
||||
- (IBAction)visitWebsite:(id)sender;
|
||||
|
||||
/*! @function visitSourceforge:
|
||||
* @discussion Takes the user to <i>http://resknife.sourceforge.net/</i>.
|
||||
/*!
|
||||
@method visitSourceforge:
|
||||
@abstract Takes the user to <i>http://resknife.sourceforge.net/</i>.
|
||||
*/
|
||||
- (IBAction)visitSourceforge:(id)sender;
|
||||
|
||||
/*! @function emailDeveloper:
|
||||
* @discussion Launches email client and inserts <i>resknife@nickshanks.com</i> into To field.
|
||||
/*!
|
||||
@method emailDeveloper:
|
||||
@abstract Launches email client and inserts <i>resknife@nickshanks.com</i> into To field.
|
||||
*/
|
||||
- (IBAction)emailDeveloper:(id)sender;
|
||||
|
||||
/*! @function showInfo:
|
||||
* @discussion Displays the Info panel stored in <b>InfoWindow.nib</b>
|
||||
/*!
|
||||
@method showInfo:
|
||||
@abstract Displays the Info panel stored in <b>InfoWindow.nib</b>
|
||||
*/
|
||||
- (IBAction)showInfo:(id)sender;
|
||||
|
||||
/*! @function showPasteboard:
|
||||
* @discussion Displays the pasteboard document, a singleton instance of class <tt>PasteboardDocument</tt>
|
||||
/*!
|
||||
@method showPasteboard:
|
||||
@abstract Displays the pasteboard document, a singleton instance of class <tt>PasteboardDocument</tt>
|
||||
*/
|
||||
- (IBAction)showPasteboard:(id)sender;
|
||||
|
||||
/*! @function showPrefs:
|
||||
* @discussion Displays the preferences panel stored in <b>PrefsWindow.nib</b>
|
||||
/*!
|
||||
@method showPrefs:
|
||||
@abstract Displays the preferences panel stored in <b>PrefsWindow.nib</b>
|
||||
*/
|
||||
- (IBAction)showPrefs:(id)sender;
|
||||
|
||||
/*! @function initUserDefaults
|
||||
* @discussion Initalises any unset user preferences to default values as read in from <b>defaults.plist</b>.
|
||||
/*!
|
||||
@method initUserDefaults
|
||||
@abstract Initalises any unset user preferences to default values as read in from <b>defaults.plist</b>.
|
||||
*/
|
||||
- (void)initUserDefaults;
|
||||
|
||||
/*! @function openAuxView
|
||||
* @discussion Accessor method for the <tt>openAuxView</tt> instance variable.
|
||||
*/
|
||||
- (NSView *)openAuxView;
|
||||
/* accessors */
|
||||
|
||||
/*! @function icons
|
||||
* @discussion Accessor method for the <tt>icons</tt> instance variable.
|
||||
/*!
|
||||
@method openPanelDelegate
|
||||
@abstract Accessor method for the <tt>openPanelDelegate</tt> instance variable.
|
||||
*/
|
||||
- (OpenPanelDelegate *)openPanelDelegate;
|
||||
|
||||
/*!
|
||||
@@method iconForResourceType:
|
||||
@abstract Returns the icon to be used throughout the UI for any given resource type.
|
||||
*/
|
||||
- (NSImage *)iconForResourceType:(NSString *)resourceType;
|
||||
|
||||
/*!
|
||||
@@method _icons
|
||||
@abstract Private accessor method for the <tt>_icons</tt> instance variable.
|
||||
*/
|
||||
- (NSMutableDictionary *)_icons;
|
||||
|
||||
/*!
|
||||
@method icons
|
||||
@abstract Accessor method for the <tt>_icons</tt> instance variable. Returns an immutable dictionary.
|
||||
*/
|
||||
- (NSDictionary *)icons;
|
||||
|
||||
@end
|
||||
/* utility methods */
|
||||
|
||||
@interface NSSavePanel (PackageBrowser)
|
||||
- (NSArray *)forksForFile:(FSRef *)fileRef;
|
||||
|
||||
@end
|
@ -1,4 +1,5 @@
|
||||
#import "ApplicationDelegate.h"
|
||||
#import "OpenPanelDelegate.h"
|
||||
#import "RKDocumentController.h"
|
||||
#import "InfoWindowController.h"
|
||||
#import "PasteboardWindowController.h"
|
||||
@ -6,8 +7,9 @@
|
||||
#import "CreateResourceSheetController.h"
|
||||
#import "ResourceDocument.h"
|
||||
#import "ResourceDataSource.h"
|
||||
#import "RKEditorRegistry.h"
|
||||
|
||||
#import "ResknifePluginProtocol.h"
|
||||
#import "ResKnifePluginProtocol.h"
|
||||
#import "RKSupportResourceRegistry.h"
|
||||
|
||||
|
||||
@ -23,42 +25,96 @@
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
// instanciate my own subclass of NSDocumentController so I can override the open dialog
|
||||
RKDocumentController *docController = [[RKDocumentController alloc] init];
|
||||
|
||||
[RKSupportResourceRegistry scanForSupportResources: [NSDocumentController sharedDocumentController]];
|
||||
[[RKDocumentController alloc] init];
|
||||
[RKSupportResourceRegistry scanForSupportResources];
|
||||
}
|
||||
|
||||
/*!
|
||||
@method awakeFromNib
|
||||
@updated 2003-10-24 NGS: moved icon caching into method called by timer (to speed up app launch time)
|
||||
*/
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
NSTableColumn *tableColumn;
|
||||
NSButtonCell *buttonCell;
|
||||
|
||||
// Part of my EvilPlanª to find out how many people use ResKnife and how often!
|
||||
int launchCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"];
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:launchCount + 1 forKey:@"LaunchCount"];
|
||||
|
||||
// save a number of icons
|
||||
icons = [[NSMutableDictionary alloc] init];
|
||||
[icons setObject:[[NSWorkspace sharedWorkspace] iconForFileType:@"TEXT"] forKey:@"TEXT"];
|
||||
[icons setObject:[[NSWorkspace sharedWorkspace] iconForFileType:@"PICT"] forKey:@"PICT"];
|
||||
[icons setObject:[[NSWorkspace sharedWorkspace] iconForFileType:@"icns"] forKey:@"icns"];
|
||||
|
||||
// set up open dialog's aux table view
|
||||
tableColumn = [forkTableView tableColumnWithIdentifier:@"parse"];
|
||||
buttonCell = [[[NSButtonCell alloc] initTextCell:@""] autorelease];
|
||||
[buttonCell setEditable:YES];
|
||||
[buttonCell setButtonType:NSSwitchButton];
|
||||
[tableColumn setDataCell:buttonCell];
|
||||
// initalise an empty icon cache and create timer used to pre-cache a number of common icons
|
||||
_icons = [[NSMutableDictionary alloc] init];
|
||||
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(precacheIcons:) userInfo:nil repeats:NO];
|
||||
|
||||
// set default preferences
|
||||
[self initUserDefaults];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[icons release];
|
||||
[_icons release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/*!
|
||||
@method precacheIcons:
|
||||
@author Nicholas Shanks
|
||||
@created 2003-10-24
|
||||
@abstract Pre-caches the icons for a number of common resource types.
|
||||
@description Icon pre-caching now uses the more sophisticated iconForResourceType: instead of obtaining the images directly from the file system (otherwise pre-cached icons would not be overridable by plug-ins). In addition it has been moved from the awakeFromNib: method into one called by a timer. This method should not be called until after the editor registry has been built.
|
||||
*/
|
||||
|
||||
- (void)precacheIcons:(NSTimer *)timer
|
||||
{
|
||||
// pre-cache a number of common icons (ignores return value, relies on iconForResourceType: to do the actual caching)
|
||||
[self iconForResourceType:@" "];
|
||||
[self iconForResourceType:@"CODE"];
|
||||
[self iconForResourceType:@"icns"];
|
||||
[self iconForResourceType:@"PICT"];
|
||||
[self iconForResourceType:@"plst"];
|
||||
[self iconForResourceType:@"snd "];
|
||||
[self iconForResourceType:@"TEXT"];
|
||||
}
|
||||
|
||||
- (NSArray *)forksForFile:(FSRef *)fileRef
|
||||
{
|
||||
if(!fileRef) return nil;
|
||||
|
||||
FSCatalogInfo catalogInfo;
|
||||
FSCatalogInfoBitmap whichInfo = kFSCatInfoNodeFlags;
|
||||
CatPositionRec forkIterator = { 0 };
|
||||
NSMutableArray *forks = [NSMutableArray array];
|
||||
|
||||
// check we have a file, not a folder
|
||||
OSErr error = FSGetCatalogInfo(fileRef, whichInfo, &catalogInfo, NULL, NULL, NULL);
|
||||
if(!error && !(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask))
|
||||
{
|
||||
// iterate over file and populate forks array
|
||||
while(error == noErr)
|
||||
{
|
||||
HFSUniStr255 forkName;
|
||||
SInt64 forkSize;
|
||||
UInt64 forkPhysicalSize; // used if opening selected fork fails to find empty forks
|
||||
|
||||
error = FSIterateForks(fileRef, &forkIterator, &forkName, &forkSize, &forkPhysicalSize);
|
||||
if(!error)
|
||||
{
|
||||
NSString *fName = [NSString stringWithCharacters:forkName.unicode length:forkName.length];
|
||||
NSNumber *fSize = [NSNumber numberWithLongLong:forkSize];
|
||||
NSNumber *fAlloc = [NSNumber numberWithUnsignedLongLong:forkPhysicalSize];
|
||||
[forks addObject:[NSDictionary dictionaryWithObjectsAndKeys:fName, @"forkname", fSize, @"forksize", fAlloc, @"forkallocation", nil]];
|
||||
}
|
||||
else if(error != errFSNoMoreItems)
|
||||
{
|
||||
NSLog(@"FSIterateForks() error: %d", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(error)
|
||||
{
|
||||
NSLog(@"FSGetCatalogInfo() error: %d", error);
|
||||
}
|
||||
return forks;
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
|
||||
{
|
||||
#pragma unused(sender)
|
||||
@ -89,8 +145,14 @@
|
||||
|
||||
- (IBAction)showAbout:(id)sender
|
||||
{
|
||||
[NSApp orderFrontStandardAboutPanel:sender];
|
||||
// get about box code from http://cocoadevcentral.com/tutorials/showpage.php?show=00000041.php
|
||||
// could do with a better about box
|
||||
/* NSWindowController *wc = [[NSWindowController alloc] initWithWindowNibName:@"AboutPanel"];
|
||||
if([(NSTextView *)[[wc window] initialFirstResponder] readRTFDFromFile:[[NSBundle mainBundle] pathForResource:@"Credits" ofType:@"rtf"]])
|
||||
{
|
||||
[[wc window] center];
|
||||
[[wc window] orderFront:nil];
|
||||
}
|
||||
else*/ [NSApp orderFrontStandardAboutPanel:sender];
|
||||
}
|
||||
|
||||
- (IBAction)visitWebsite:(id)sender
|
||||
@ -160,26 +222,94 @@
|
||||
[defaults synchronize];
|
||||
}
|
||||
|
||||
- (NSView *)openAuxView
|
||||
- (OpenPanelDelegate *)openPanelDelegate
|
||||
{
|
||||
return openAuxView;
|
||||
return openPanelDelegate;
|
||||
}
|
||||
|
||||
/*!
|
||||
@method iconForResourceType:
|
||||
@author Nicholas Shanks
|
||||
@created 2003-10-24
|
||||
@abstract Manages the cache of icons used for representing resource types.
|
||||
@description This method loads icons for each resource type from a variety of places and caches them for faster access. Your plug-in may be asked to return an icon for any resource type it declares it can edit. To implement this, your plug should respond to the iconForResourceType: selector with the same method signature as this method. The icons can be in any format recognised by NSImage. Alternativly, just leave your icons in "Your.plugin/Contents/Resources/Resource Type Icons/" (or any equivalent localised directory) with a name like "TYPE.tiff" and ResKnife will retreive them automatically.
|
||||
@pending I don't like the name I chose here for the resource type icons directory. Can anyone think of something better?
|
||||
*/
|
||||
|
||||
- (NSImage *)iconForResourceType:(NSString *)resourceType
|
||||
{
|
||||
// check if we have image in cache already
|
||||
NSImage *icon = nil;
|
||||
if([resourceType isEqualToString:@""])
|
||||
resourceType = nil;
|
||||
|
||||
if(resourceType);
|
||||
icon = [[self _icons] valueForKey:resourceType];
|
||||
if(!icon)
|
||||
{
|
||||
NSString *iconPath = nil;
|
||||
|
||||
// try to load icon from the default editor for that type
|
||||
Class editor = [[RKEditorRegistry defaultRegistry] editorForType:resourceType];
|
||||
if(editor && resourceType)
|
||||
{
|
||||
// ask politly for icon
|
||||
if([editor respondsToSelector:@selector(iconForResourceType:)])
|
||||
icon = [editor iconForResourceType:resourceType];
|
||||
|
||||
// try getting it myself
|
||||
if(!icon)
|
||||
{
|
||||
iconPath = [[NSBundle bundleForClass:editor] pathForResource:resourceType ofType:nil inDirectory:@"Resource Type Icons"];
|
||||
if(iconPath)
|
||||
icon = [[[NSImage alloc] initWithContentsOfFile:iconPath] autorelease];
|
||||
}
|
||||
}
|
||||
|
||||
// try to load icon from the ResKnife app bundle itself
|
||||
if(!icon && resourceType)
|
||||
{
|
||||
iconPath = [[NSBundle mainBundle] pathForResource:resourceType ofType:nil inDirectory:@"Resource Type Icons"];
|
||||
if(iconPath)
|
||||
icon = [[[NSImage alloc] initWithContentsOfFile:iconPath] autorelease];
|
||||
}
|
||||
|
||||
// try to retreive from file system (after first mangling the type through our converter strings file)
|
||||
if(!icon && resourceType)
|
||||
{
|
||||
NSString *fileType = [[NSBundle mainBundle] localizedStringForKey:resourceType value:@"" table:@"Resource Type Mappings"];
|
||||
NSRange range = [fileType rangeOfString:@"."];
|
||||
if(range.location == NSNotFound)
|
||||
icon = [[NSWorkspace sharedWorkspace] iconForFileType:fileType];
|
||||
else // a '.' character in a file type means ResKnife should look for a bundle icon with fileType as the bundle's identifier
|
||||
{
|
||||
NSString *bundlePath = [[NSBundle bundleWithIdentifier:fileType] bundlePath];
|
||||
if(bundlePath)
|
||||
icon = [[NSWorkspace sharedWorkspace] iconForFile:bundlePath];
|
||||
}
|
||||
}
|
||||
|
||||
// if we still don't have an icon, try to get the generic one - this is what icon represented forks get
|
||||
// if(!icon) icon = [NSImage imageNamed:@"NSMysteryDocument"];
|
||||
if(!icon) icon = [[NSWorkspace sharedWorkspace] iconForFileType:@"' '"];
|
||||
|
||||
// save the newly retreived icon in the cache
|
||||
if(icon && resourceType)
|
||||
[[self _icons] setObject:icon forKey:resourceType];
|
||||
}
|
||||
|
||||
// return the cached icon, or nil if none was found
|
||||
return icon;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)_icons
|
||||
{
|
||||
return _icons;
|
||||
}
|
||||
|
||||
- (NSDictionary *)icons
|
||||
{
|
||||
return icons;
|
||||
return [NSDictionary dictionaryWithDictionary:[self _icons]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSSavePanel (PackageBrowser)
|
||||
|
||||
/* Don't tell anyone I did this... */
|
||||
|
||||
/*- (void)setTreatsFilePackagesAsDirectories:(BOOL)flag
|
||||
{
|
||||
#pragma unused( flag )
|
||||
_spFlags.treatsFilePackagesAsDirectories = YES;
|
||||
}*/
|
||||
|
||||
@end
|
@ -5,21 +5,13 @@
|
||||
|
||||
@implementation CreateResourceSheetController
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
controlTextDidChange:
|
||||
Someone changed the control ID edit field. Check whether this is
|
||||
a unique ID and appropriately enable the "create" button.
|
||||
|
||||
Check "notification" against being nil, which is how we call it when
|
||||
we need to explicitly update the enabled state of the "create" button.
|
||||
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Commented, changed to use data source's resourceOfType
|
||||
instead of directly messing with the resource list's
|
||||
enumerator Removed ID > 0 check -- negative IDs are
|
||||
allowed as well.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*!
|
||||
@method controlTextDidChange:
|
||||
@abstract Handles updating of the 'Create' button when valid values are present in the sheet's fields.
|
||||
@updated 2003-08-01 UK: Changed to use data source's resourceOfType instead of directly messing with the resource list's enumerator.
|
||||
@updated 2003-08-01 UK: Removed ID > 0 check -- negative IDs are allowed as well.<br/><small>Note from Nick: IIRC this was there as a workaround for another bug which prohibited negative IDs from being used. Not sure if that got fixed though :)</small>
|
||||
@description Someone changed the control ID edit field. Check whether this is a unique ID and appropriately enable the "create" button.</p><p>Check "notification" against being nil, which is how we call it when we need to explicitly update the enabled state of the "create" button.
|
||||
*/
|
||||
|
||||
- (void)controlTextDidChange:(NSNotification *)notification
|
||||
{
|
||||
@ -37,16 +29,12 @@
|
||||
[createButton setEnabled:enableButton];
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
showCreateResourceSheet:
|
||||
Show our sheet and set it up before that.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Commented, made it "fake" a popup selection so
|
||||
type field and popup match. Made it suggest an unused
|
||||
resource ID.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*!
|
||||
@method showCreateResourceSheet:
|
||||
@abstract Shows the sheet allowing the user to define the properties of a new resource.
|
||||
@updated 2003-08-01 UK: Made it "fake" a popup selection so type field and popup match.
|
||||
@updated 2003-08-01 UK: Made it suggest an unused resource ID.
|
||||
*/
|
||||
|
||||
- (void)showCreateResourceSheet:(ResourceDocument *)sheetDoc
|
||||
{
|
||||
@ -54,13 +42,18 @@
|
||||
document = sheetDoc;
|
||||
[NSApp beginSheet:[self window] modalForWindow:[document mainWindow] modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
||||
[resIDView setObjectValue:[[document dataSource] uniqueIDForType:[typeView stringValue]]];
|
||||
[self typePopupSelection: typePopup]; // Puts current popup value in text field and updates state of "create" button.
|
||||
|
||||
// put current popup value in text field and updates state of "create" button.
|
||||
[self typePopupSelection:typePopup];
|
||||
}
|
||||
|
||||
- (IBAction)hideCreateResourceSheet:(id)sender
|
||||
{
|
||||
if(sender == createButton)
|
||||
{
|
||||
// bug should be using cell's tag rather than position (so cells can be moved around if needed)
|
||||
// attributes ^= [[attributesMatrix cellAtRow:0 column:0] intValue]? [[attributesMatrix cellAtRow:0 column:0] tag]:0;
|
||||
|
||||
unsigned short attributes = 0;
|
||||
attributes ^= [[attributesMatrix cellAtRow:0 column:0] intValue]? resPreload:0;
|
||||
attributes ^= [[attributesMatrix cellAtRow:1 column:0] intValue]? resPurgeable:0;
|
||||
@ -68,26 +61,24 @@
|
||||
attributes ^= [[attributesMatrix cellAtRow:0 column:1] intValue]? resSysHeap:0;
|
||||
attributes ^= [[attributesMatrix cellAtRow:1 column:1] intValue]? resProtected:0;
|
||||
|
||||
Resource *resource = [Resource resourceOfType:[typeView stringValue] andID:[NSNumber numberWithShort:(short) [resIDView intValue]] withName:[nameView stringValue] andAttributes:[NSNumber numberWithUnsignedShort:attributes]];
|
||||
[resource setDocumentName:[document displayName]];
|
||||
[[document undoManager] beginUndoGrouping];
|
||||
[[document dataSource] addResource:[Resource resourceOfType:[typeView stringValue] andID:[NSNumber numberWithShort:(short) [resIDView intValue]] withName:[nameView stringValue] andAttributes:[NSNumber numberWithUnsignedShort:attributes]]];
|
||||
[[document dataSource] addResource:resource];
|
||||
if([[nameView stringValue] length] == 0)
|
||||
[[document undoManager] setActionName:NSLocalizedString(@"Create Resource", nil)];
|
||||
else [[document undoManager] setActionName:[NSString stringWithFormat:NSLocalizedString(@"Create Resource Ò%@Ó", nil), [nameView stringValue]]];
|
||||
else [[document undoManager] setActionName:[NSString stringWithFormat:NSLocalizedString(@"Create Resource '%@'", nil), [nameView stringValue]]];
|
||||
[[document undoManager] endUndoGrouping];
|
||||
}
|
||||
[[self window] orderOut:nil];
|
||||
[NSApp endSheet:[self window]];
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
typePopupSelection:
|
||||
Someone chose an item from our "res type" popup menu. Update our
|
||||
edit field to show that.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Commented, made it update state of "create" button..
|
||||
-------------------------------------------------------------------------- */
|
||||
/*!
|
||||
@method typePopupSelection:
|
||||
@abstract Updates the edit text field when the type pop-up selection is changed.
|
||||
@updated 2003-08-01 UK: Commented, made it update state of "create" button.
|
||||
*/
|
||||
|
||||
- (IBAction)typePopupSelection:(id)sender
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ enum Attributes
|
||||
- (void)updateInfoWindow;
|
||||
- (void)setMainWindow:(NSWindow *)mainWindow;
|
||||
- (IBAction)attributesChanged:(id)sender;
|
||||
- (IBAction)nameChanged: (id)sender;
|
||||
- (IBAction)nameDidChange:(id)sender;
|
||||
- (void)resourceAttributesDidChange:(NSNotification *)notification;
|
||||
- (void)documentInfoDidChange:(NSNotification *)notification;
|
||||
|
||||
@ -46,7 +46,7 @@ enum Attributes
|
||||
@interface NSWindowController (InfoWindowAdditions)
|
||||
|
||||
/*! @function resource
|
||||
@discussion Your plug-in should override this method to return the resource it's editing. Default implementation returns nil.
|
||||
@discussion Your plug-in should override this method to return the primary resource it's editing. Default implementation returns nil.
|
||||
*/
|
||||
- (Resource *)resource;
|
||||
|
||||
|
@ -2,18 +2,12 @@
|
||||
#import <Carbon/Carbon.h> // Actually I only need CarbonCore.framework, but <Carbon/CarbonCore.h> and <CarbonCore/CarbonCore.h> don't work, so I don't know what else to do
|
||||
#import "ResourceDocument.h"
|
||||
#import "Resource.h"
|
||||
#import "ApplicationDelegate.h"
|
||||
#import "NSOutlineView-SelectedItems.h"
|
||||
#import "MoreFilesX.h"
|
||||
|
||||
@implementation InfoWindowController
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [self initWithWindowNibName:@"InfoWindow"];
|
||||
if( self ) [self setWindowFrameAutosaveName:@"InfoWindow"];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
@ -40,6 +34,13 @@
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentInfoDidChange:) name:DocumentInfoDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
@method updateInfoWindow
|
||||
@updated 2003-11-06 NGS: Fixed creator/type handling.
|
||||
@updated 2003-10-26 NGS: Now asks app delegate for icon instead of NSWorkspace.
|
||||
@updated 2003-10-26 NGS: Improved document name & icon display.
|
||||
*/
|
||||
|
||||
- (void)updateInfoWindow
|
||||
{
|
||||
[nameView setEditable:(selectedResource != nil)];
|
||||
@ -47,16 +48,19 @@
|
||||
|
||||
if(selectedResource)
|
||||
{
|
||||
[[self window] setTitle:@"Resource Info"];
|
||||
[placeholderView setContentView:resourceView];
|
||||
// set UI values
|
||||
[[self window] setTitle:NSLocalizedString(@"Resource Info",nil)];
|
||||
[nameView setStringValue:[selectedResource name]];
|
||||
[iconView setImage:[[NSWorkspace sharedWorkspace] iconForFileType:[selectedResource type]]];
|
||||
[iconView setImage:[(ApplicationDelegate *)[NSApp delegate] iconForResourceType:[selectedResource type]]];
|
||||
[[attributesMatrix cellAtRow:changedBox column:0] setState:[[selectedResource attributes] shortValue] & resChanged];
|
||||
[[attributesMatrix cellAtRow:preloadBox column:0] setState:[[selectedResource attributes] shortValue] & resPreload];
|
||||
[[attributesMatrix cellAtRow:protectedBox column:0] setState:[[selectedResource attributes] shortValue] & resProtected];
|
||||
[[attributesMatrix cellAtRow:lockedBox column:0] setState:[[selectedResource attributes] shortValue] & resLocked];
|
||||
[[attributesMatrix cellAtRow:purgableBox column:0] setState:[[selectedResource attributes] shortValue] & resPurgeable];
|
||||
[[attributesMatrix cellAtRow:systemHeapBox column:0] setState:[[selectedResource attributes] shortValue] & resSysHeap];
|
||||
|
||||
// swap box
|
||||
[placeholderView setContentView:resourceView];
|
||||
}
|
||||
else if(currentDocument != nil)
|
||||
{
|
||||
@ -65,23 +69,41 @@
|
||||
FSRef *fileRef = (FSRef *) NewPtrClear(sizeof(FSRef));
|
||||
if(fileRef && [currentDocument fileName])
|
||||
{
|
||||
OSStatus error = FSPathMakeRef( [[currentDocument fileName] cString], fileRef, nil );
|
||||
OSStatus error = FSPathMakeRef([[currentDocument fileName] fileSystemRepresentation], fileRef, nil);
|
||||
if(!error) FSGetForkSizes(fileRef, &dataLogicalSize, &rsrcLogicalSize);
|
||||
}
|
||||
if(fileRef) DisposePtr((Ptr) fileRef);
|
||||
|
||||
// set info window elements to correct values
|
||||
[[self window] setTitle:@"Document Info"];
|
||||
[[self window] setTitle:NSLocalizedString(@"Document Info",nil)];
|
||||
if([currentDocument fileName]) // document has been saved
|
||||
{
|
||||
[iconView setImage:[[NSWorkspace sharedWorkspace] iconForFile:[currentDocument fileName]]];
|
||||
[nameView setStringValue:[[currentDocument fileName] lastPathComponent]];
|
||||
}
|
||||
else // new, untitled document
|
||||
{
|
||||
[iconView setImage:[NSImage imageNamed:@"Resource file"]];
|
||||
[nameView setStringValue:[currentDocument fileName]? [[currentDocument fileName] lastPathComponent]:[currentDocument displayName]];
|
||||
[[filePropertyForm cellAtIndex:0] setStringValue:[currentDocument creator]];
|
||||
[[filePropertyForm cellAtIndex:1] setStringValue:[currentDocument type]];
|
||||
[nameView setStringValue:[currentDocument displayName]];
|
||||
}
|
||||
[currentDocument creator];
|
||||
[[NSString alloc] initWithData:[currentDocument creator] encoding:NSMacOSRomanStringEncoding];
|
||||
[[filePropertyForm cellAtIndex:0] setStringValue:[[[NSString alloc] initWithData:[currentDocument creator] encoding:NSMacOSRomanStringEncoding] autorelease]];
|
||||
[[filePropertyForm cellAtIndex:1] setStringValue:[[[NSString alloc] initWithData:[currentDocument type] encoding:NSMacOSRomanStringEncoding] autorelease]];
|
||||
// [[filePropertyForm cellAtIndex:2] setObjectValue:[NSNumber numberWithUnsignedLongLong:dataLogicalSize]];
|
||||
// [[filePropertyForm cellAtIndex:3] setObjectValue:[NSNumber numberWithUnsignedLongLong:rsrcLogicalSize]];
|
||||
[[filePropertyForm cellAtIndex:2] setStringValue:[[NSNumber numberWithUnsignedLongLong:dataLogicalSize] description]];
|
||||
[[filePropertyForm cellAtIndex:3] setStringValue:[[NSNumber numberWithUnsignedLongLong:rsrcLogicalSize] description]];
|
||||
|
||||
// swap box
|
||||
[placeholderView setContentView:documentView];
|
||||
}
|
||||
else
|
||||
{
|
||||
[iconView setImage:nil];
|
||||
[nameView setStringValue:nil];
|
||||
[placeholderView setContentView:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setMainWindow:(NSWindow *)mainWindow
|
||||
@ -106,8 +128,8 @@
|
||||
- (void)selectedResourceChanged:(NSNotification *)notification
|
||||
{
|
||||
if(![[nameView stringValue] isEqualToString:[selectedResource name]])
|
||||
[self nameChanged:nameView];
|
||||
selectedResource = [[notification object] selectedItem];
|
||||
[self nameDidChange:nameView];
|
||||
selectedResource = (Resource *) [[notification object] selectedItem];
|
||||
[self updateInfoWindow];
|
||||
}
|
||||
|
||||
@ -124,15 +146,13 @@
|
||||
[selectedResource setAttributes:[NSNumber numberWithShort:number]];
|
||||
}
|
||||
|
||||
-(IBAction) nameChanged: (id)sender
|
||||
- (IBAction)nameDidChange:(id)sender
|
||||
{
|
||||
[selectedResource setName:[nameView stringValue]];
|
||||
}
|
||||
|
||||
- (void)resourceAttributesDidChange:(NSNotification *)notification;
|
||||
{
|
||||
if( ![[nameView stringValue] isEqualToString: [selectedResource name]] )
|
||||
[self nameChanged:nameView];
|
||||
[self updateInfoWindow];
|
||||
}
|
||||
|
||||
@ -140,7 +160,7 @@
|
||||
{
|
||||
static InfoWindowController *sharedInfoWindowController = nil;
|
||||
if(!sharedInfoWindowController)
|
||||
sharedInfoWindowController = [[InfoWindowController allocWithZone:[self zone]] init];
|
||||
sharedInfoWindowController = [[InfoWindowController allocWithZone:[self zone]] initWithWindowNibName:@"InfoWindow"];
|
||||
return sharedInfoWindowController;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,9 @@
|
||||
#import "NSOutlineView-SelectedItems.h"
|
||||
#import "Resource.h"
|
||||
|
||||
/* NameFormatter has been deprecated (it never did what I wanted anyway :-) */
|
||||
/* functionality is now in -outlineView:willDisplayCell:forTableColumn:item: */
|
||||
|
||||
@implementation NameFormatter
|
||||
|
||||
- (NSString *)stringForObjectValue:(id)obj
|
||||
|
@ -1,19 +0,0 @@
|
||||
/* OpenFileDataSource */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface OpenFileDataSource : NSObject
|
||||
{
|
||||
IBOutlet NSTableView *forkTableView;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface OpenPanelDelegate : NSObject
|
||||
{
|
||||
id originalDelegate;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface NSSavePanel (ResKnife)
|
||||
- (NSBrowser *)browser;
|
||||
@end
|
@ -1,113 +0,0 @@
|
||||
#import "OpenFileDataSource.h"
|
||||
#import <unistd.h>
|
||||
#import <sys/attr.h>
|
||||
|
||||
struct directoryinfo {
|
||||
unsigned long length;
|
||||
u_int32_t dirid;
|
||||
};
|
||||
|
||||
struct dunnowhat
|
||||
{
|
||||
unsigned long length;
|
||||
u_int32_t data1;
|
||||
u_int32_t data2;
|
||||
u_int32_t data3;
|
||||
u_int32_t data4;
|
||||
u_int32_t data5;
|
||||
u_int32_t data6;
|
||||
};
|
||||
|
||||
@implementation OpenFileDataSource
|
||||
|
||||
//get action method and target of browser, intercept (or re-route and call it myself)
|
||||
|
||||
/* NSTableView data source protocol implementation */
|
||||
- (int)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
//NSBrowser *browser = [(NSOpenPanel *)[tableView window] browser];
|
||||
//if( [[browser selectedCells] count] == 1 )
|
||||
{
|
||||
// only one file is selected, parse it for forks
|
||||
/* const char *path = [[browser path] cString];
|
||||
struct attrlist attributes;
|
||||
struct directoryinfo fileinfo;
|
||||
|
||||
NSLog( @"%s", path );
|
||||
// memset( &attributes, 0, sizeof(struct attrlist) );
|
||||
bzero( &attributes, sizeof(struct attrlist) );
|
||||
attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||
// attributes.fileattr = ATTR_FILE_FORKCOUNT;
|
||||
attributes.commonattr = ATTR_CMN_OBJID;
|
||||
int result = getattrlist( path, &attributes, &fileinfo, sizeof(struct directoryinfo), 0 );
|
||||
NSLog( @"%d", result );
|
||||
if( result != 0 ) return 0;
|
||||
NSLog( @"%d", fileinfo.length );
|
||||
NSLog( @"%d", fileinfo.dirid );
|
||||
*/
|
||||
/*struct attrlist alist;
|
||||
struct directoryinfo dirinfo;
|
||||
char *path = [[browser path] cString];
|
||||
bzero(&alist, sizeof(alist));
|
||||
alist.bitmapcount = 5;
|
||||
alist.commonattr = ATTR_CMN_OBJID;
|
||||
int result = getattrlist(path, &alist, &dirinfo, sizeof(dirinfo), 0);
|
||||
printf("result: %d; directory id: %lu; %s\n", result, dirinfo.dirid, path);
|
||||
|
||||
return 3;*/
|
||||
}
|
||||
|
||||
// multiple/no selected files, return nothing
|
||||
/*else*/ return 0;
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
NSLog( [browser path] );
|
||||
CatPositionRec forkIterator;
|
||||
forkIterator.initialize = 0;
|
||||
FSIterateForks( FSRef *ref, &forkIterator, NULL, NULL, NULL );
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
@implementation OpenPanelDelegate
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
|
||||
{
|
||||
/* NSMethodSignature *sig;
|
||||
NS_DURING
|
||||
sig = [super methodSignatureForSelector:selector];
|
||||
NS_HANDLER
|
||||
sig = [originalDelegate methodSignatureForSelector:selector];
|
||||
NS_ENDHANDLER
|
||||
return sig; */
|
||||
return [originalDelegate methodSignatureForSelector:selector];
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)invocation
|
||||
{
|
||||
if( [originalDelegate respondsToSelector:[invocation selector]] )
|
||||
[invocation invokeWithTarget:originalDelegate];
|
||||
else [self doesNotRecognizeSelector:[invocation selector]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSSavePanel (ResKnife)
|
||||
|
||||
- (NSBrowser *)browser
|
||||
{
|
||||
return nil; //return _browser;
|
||||
}
|
||||
|
||||
@end
|
43
Cocoa/Classes/OpenPanelDelegate.h
Normal file
@ -0,0 +1,43 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface OpenPanelDelegate : NSObject
|
||||
{
|
||||
/*! @var openPanelAccessoryView Accessory view for <tt>NSOpenPanels</tt>. */
|
||||
IBOutlet NSView *openPanelAccessoryView;
|
||||
/*! @var forkTableView Table view inside <tt>openPanelAccessoryView</tt>. */
|
||||
IBOutlet NSTableView *forkTableView;
|
||||
/*! @var addForkButton Button for adding forks to a file. */
|
||||
IBOutlet NSButton *addForkButton;
|
||||
/*! @var removeForkButton Button for removing forks from a file. */
|
||||
IBOutlet NSButton *removeForkButton;
|
||||
|
||||
/*! @var forks Array of forks representing the currently selected file. */
|
||||
NSMutableArray *forks;
|
||||
/*! @var readOpenPanelForFork Flag indicating whether ResKnife should ask for a fork to parse in a secondary dialog (false) or obtain it from the selected item in the open dialog (true). */
|
||||
BOOL readOpenPanelForFork;
|
||||
}
|
||||
|
||||
/* actions from aux view controls */
|
||||
|
||||
- (IBAction)addFork:(id)sender;
|
||||
- (IBAction)removeFork:(id)sender;
|
||||
|
||||
/* accessors */
|
||||
|
||||
/*!
|
||||
@method openPanelAccessoryView
|
||||
@abstract Accessor method for the <tt>openPanelAccessoryView</tt> instance variable.
|
||||
*/
|
||||
- (NSView *)openPanelAccessoryView;
|
||||
|
||||
/*!
|
||||
@method forkTableView
|
||||
@abstract Accessor method for the <tt>forkTableView</tt> instance variable.
|
||||
*/
|
||||
- (NSTableView *)forkTableView;
|
||||
|
||||
- (NSArray *)forks;
|
||||
- (void)setReadOpenPanelForFork:(BOOL)flag;
|
||||
- (BOOL)readOpenPanelForFork;
|
||||
|
||||
@end
|
131
Cocoa/Classes/OpenPanelDelegate.m
Normal file
@ -0,0 +1,131 @@
|
||||
#import "OpenPanelDelegate.h"
|
||||
#import "ApplicationDelegate.h"
|
||||
#import "SizeFormatter.h"
|
||||
#import "../Categories/NSString-FSSpec.h"
|
||||
|
||||
@implementation OpenPanelDelegate
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if(self)
|
||||
{
|
||||
forks = [[NSMutableArray alloc] init];
|
||||
readOpenPanelForFork = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
// remove this when functionality actually works
|
||||
[addForkButton setEnabled:NO];
|
||||
[removeForkButton setEnabled:NO];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[forks release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// open panel delegate method
|
||||
- (void)panelSelectionDidChange:(id)sender
|
||||
{
|
||||
[forks setArray:[(ApplicationDelegate *)[NSApp delegate] forksForFile:[[sender filename] createFSRef]]];
|
||||
[forkTableView reloadData];
|
||||
}
|
||||
|
||||
- (BOOL)readOpenPanelForFork
|
||||
{
|
||||
return readOpenPanelForFork;
|
||||
}
|
||||
|
||||
- (void)setReadOpenPanelForFork:(BOOL)flag
|
||||
{
|
||||
readOpenPanelForFork = flag;
|
||||
}
|
||||
|
||||
// table view data source methods
|
||||
- (int)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
return [forks count];
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
|
||||
{
|
||||
// return object in array
|
||||
if(row < [forks count])
|
||||
{
|
||||
if([[tableColumn identifier] isEqualToString:@"forkname"])
|
||||
{
|
||||
NSString *forkName = nil;
|
||||
HFSUniStr255 *resourceForkName = (HFSUniStr255 *) NewPtrClear(sizeof(HFSUniStr255));
|
||||
OSErr error = FSGetResourceForkName(resourceForkName);
|
||||
forkName = [(NSDictionary *)[forks objectAtIndex:row] objectForKey:[tableColumn identifier]];
|
||||
|
||||
// return custom names for data and resource forks
|
||||
if([forkName isEqualToString:@""])
|
||||
forkName = NSLocalizedString(@"Data Fork", nil);
|
||||
else if(!error && [forkName isEqualToString:[NSString stringWithCharacters:resourceForkName->unicode length:resourceForkName->length]])
|
||||
forkName = NSLocalizedString(@"Resource Fork", nil);
|
||||
|
||||
DisposePtr((Ptr) resourceForkName);
|
||||
return forkName;
|
||||
}
|
||||
|
||||
// return default value otherwise
|
||||
return [(NSDictionary *)[forks objectAtIndex:row] objectForKey:[tableColumn identifier]];
|
||||
}
|
||||
else return nil;
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
|
||||
{
|
||||
if([[tableColumn identifier] isEqualToString:@"forkname"])
|
||||
{
|
||||
// update forks array
|
||||
// create fork with new name
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)addFork:(id)sender
|
||||
{
|
||||
// add placeholder to forks array
|
||||
[forks addObject:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"UNTITLED_FORK", nil), @"forkname", [NSNumber numberWithInt:0], @"forksize", [NSNumber numberWithInt:0], @"forkallocation", nil]];
|
||||
[forkTableView noteNumberOfRowsChanged];
|
||||
[forkTableView reloadData];
|
||||
|
||||
// start editing placeholder
|
||||
[forkTableView selectRow:[forks count]-1 byExtendingSelection:NO];
|
||||
[forkTableView editColumn:0 row:[forks count]-1 withEvent:nil select:YES];
|
||||
}
|
||||
|
||||
- (IBAction)removeFork:(id)sender
|
||||
{
|
||||
// display warning
|
||||
// delete fork
|
||||
|
||||
// update table view
|
||||
[forks removeObjectAtIndex:[forkTableView selectedRow]+1];
|
||||
[forkTableView noteNumberOfRowsChanged];
|
||||
[forkTableView reloadData];
|
||||
}
|
||||
|
||||
- (NSArray *)forks
|
||||
{
|
||||
// returns an immutable array
|
||||
return [NSArray arrayWithArray:forks];
|
||||
}
|
||||
|
||||
- (NSView *)openPanelAccessoryView
|
||||
{
|
||||
return openPanelAccessoryView;
|
||||
}
|
||||
|
||||
- (NSTableView *)forkTableView
|
||||
{
|
||||
return forkTableView;
|
||||
}
|
||||
|
||||
@end
|
@ -1,5 +1,4 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "NameFormatter.h"
|
||||
#import "SizeFormatter.h"
|
||||
#import "AttributesFormatter.h"
|
||||
|
||||
@ -8,7 +7,7 @@
|
||||
@interface OutlineViewDelegate : NSObject
|
||||
{
|
||||
IBOutlet NSWindow *window;
|
||||
IBOutlet NameFormatter *nameFormatter;
|
||||
IBOutlet NSOutlineView *outlineView;
|
||||
IBOutlet SizeFormatter *sizeFormatter;
|
||||
IBOutlet AttributesFormatter *attributesFormatter;
|
||||
}
|
||||
@ -18,9 +17,5 @@ int compareResourcesDescending( Resource *r1, Resource *r2, void *context );
|
||||
|
||||
@end
|
||||
|
||||
@interface NSOutlineView (OutlineSortView)
|
||||
- (void)swapForOutlineSortView;
|
||||
@end
|
||||
|
||||
@interface OutlineSortView : NSOutlineView
|
||||
@interface RKOutlineView : NSOutlineView
|
||||
@end
|
@ -1,11 +1,42 @@
|
||||
#import "OutlineViewDelegate.h"
|
||||
#import "Resource.h"
|
||||
#import "ResourceDocument.h"
|
||||
#import "ResourceDataSource.h"
|
||||
#import "ResourceNameCell.h"
|
||||
#import "ApplicationDelegate.h"
|
||||
|
||||
@implementation OutlineViewDelegate
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if(!self) return nil;
|
||||
if(NSAppKitVersionNumber >= 700.0) // darwin 7.0 == Mac OS 10.3, needed for -setPlaceholderString:
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatePlaceholder:) name:ResourceNameDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatePlaceholder:) name:ResourceTypeDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatePlaceholder:) name:ResourceIDDidChangeNotification object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updatePlaceholder:(NSNotification *)notification
|
||||
{
|
||||
Resource *resource = [notification object];
|
||||
ResourceNameCell *cell = (ResourceNameCell *) [[outlineView tableColumnWithIdentifier:@"name"] dataCellForRow:[outlineView rowForItem:resource]];
|
||||
if([[resource name] isEqualToString:@""])
|
||||
{
|
||||
if([[resource resID] shortValue] == -16455)
|
||||
[cell setPlaceholderString:NSLocalizedString(@"Custom Icon", nil)];
|
||||
else [cell setPlaceholderString:NSLocalizedString(@"Untitled Resource", nil)];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@method tableView:didClickTableColumn:
|
||||
@pending not needed in 10.3+, use existing sort functionality
|
||||
*/
|
||||
|
||||
- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn
|
||||
{
|
||||
NSArray *newResources;
|
||||
@ -15,103 +46,148 @@
|
||||
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]];
|
||||
}
|
||||
newResources = [oldResources sortedArrayUsingFunction:compareResourcesAscending context:[tableColumn identifier]];
|
||||
else newResources = [oldResources sortedArrayUsingFunction:compareResourcesDescending context:[tableColumn identifier]];
|
||||
|
||||
// swap new array for old one
|
||||
[(ResourceDataSource *)[tableView dataSource] setResources:[NSMutableArray arrayWithArray:newResources]];
|
||||
[tableView reloadData];
|
||||
}
|
||||
|
||||
/*!
|
||||
@function compareResourcesAscending
|
||||
@updated 2003-10-25 NGS: now uses KVC methods to obtain the strings to compare
|
||||
*/
|
||||
|
||||
int compareResourcesAscending(Resource *r1, Resource *r2, void *context)
|
||||
{
|
||||
NSString *key = (NSString *)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
|
||||
{
|
||||
if([key isEqualToString:@"name"] || [key isEqualToString:@"type"])
|
||||
return [(NSString *)[r1 valueForKey:key] caseInsensitiveCompare:(NSString *)[r2 valueForKey:key]];
|
||||
// compare two NSNumbers (or any other class)
|
||||
return [(NSNumber *)[r1 performSelector:sel] compare: (NSNumber *)[r2 performSelector:sel]];
|
||||
}
|
||||
else return [(NSNumber *)[r1 valueForKey:key] compare:(NSNumber *)[r2 valueForKey:key]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@function compareResourcesDescending
|
||||
@updated 2003-10-25 NGS: now uses KVC methods to obtain the strings to compare
|
||||
*/
|
||||
|
||||
int compareResourcesDescending(Resource *r1, Resource *r2, void *context)
|
||||
{
|
||||
NSString *key = (NSString *)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
|
||||
{
|
||||
if([key isEqualToString:@"name"] || [key isEqualToString:@"type"])
|
||||
return -1 * [(NSString *)[r1 valueForKey:key] caseInsensitiveCompare: (NSString *)[r2 valueForKey:key]];
|
||||
// compare two NSNumbers (or any other class)
|
||||
return -1 * [(NSNumber *)[r1 performSelector:sel] compare: (NSNumber *)[r2 performSelector:sel]];
|
||||
}
|
||||
else return -1 * [(NSNumber *)[r1 valueForKey:key] compare: (NSNumber *)[r2 valueForKey:key]];
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||
{
|
||||
return YES;
|
||||
if([[tableColumn identifier] isEqualToString:@"size"] || [[tableColumn identifier] isEqualToString:@"attributes"])
|
||||
return NO;
|
||||
else return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@method outlineView:willDisplayCell:forTableColumn:item:
|
||||
@updated 2003-10-25 NGS: Moved functionality of NameFormatter into this method, removed NameFormatter class.
|
||||
@updated 2003-10-24 NGS: Swapped row colours so first row is white (as per 10.3), conditionalised drawing line background colours to system versions < 10.3, since in 10.3 it is handled by the nib file.
|
||||
@updated 2003-10-24 NGS: Added iconForResourceType method to app delegate instead of interrogating the cache here.
|
||||
@pending remove setting of the cell formatter when that capability is in interface builder
|
||||
*/
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||
{
|
||||
int row = [outlineView rowForItem:item];
|
||||
Resource *resource = (Resource *)item;
|
||||
NSString *identifier = [tableColumn identifier];
|
||||
if( [identifier isEqualToString:@"name"] ) [cell setFormatter:nameFormatter];
|
||||
else if( [identifier isEqualToString:@"size"] ) [cell setFormatter:sizeFormatter];
|
||||
|
||||
// set formatters for cells (remove when IB can set a formatter for an entire table column)
|
||||
if([identifier isEqualToString:@"size"]) [cell setFormatter:sizeFormatter];
|
||||
else if([identifier isEqualToString:@"attributes"]) [cell setFormatter:attributesFormatter];
|
||||
|
||||
// set resource icon
|
||||
if([identifier isEqualToString:@"name"])
|
||||
{
|
||||
// [(ResourceNameCell *)cell setImage:[NSImage imageNamed:@"Resource file"]];
|
||||
// [(ResourceNameCell *)cell setImage:[[NSWorkspace sharedWorkspace] iconForFileType:[(Resource *)item type]]];
|
||||
[(ResourceNameCell *)cell setImage:[[(ApplicationDelegate *)[NSApp delegate] icons] valueForKey:[(Resource *)item type]]];
|
||||
}
|
||||
if(![resource representedFork])
|
||||
[(ResourceNameCell *)cell setImage:[(ApplicationDelegate *)[NSApp delegate] iconForResourceType:[resource type]]];
|
||||
else [(ResourceNameCell *)cell setImage:[(ApplicationDelegate *)[NSApp delegate] iconForResourceType:nil]];
|
||||
|
||||
if( row % 2 )
|
||||
if([[resource name] isEqualToString:@""])
|
||||
{
|
||||
[cell setDrawsBackground:NO];
|
||||
[cell setBackgroundColor:[NSColor whiteColor]];
|
||||
if([cell respondsToSelector:@selector(setPlaceholderString:)]) // 10.3+
|
||||
{
|
||||
// 10.3+ uses placeholder strings
|
||||
if([[resource resID] shortValue] == -16455) // don't bother checking type since there are too many icon types
|
||||
[cell setPlaceholderString:NSLocalizedString(@"Custom Icon", nil)];
|
||||
else if([[resource type] isEqualToString:@"carb"] && [[resource resID] shortValue] == 0)
|
||||
[cell setPlaceholderString:NSLocalizedString(@"Carbon Identifier", nil)];
|
||||
else if([[resource type] isEqualToString:@"pnot"] && [[resource resID] shortValue] == 0)
|
||||
[cell setPlaceholderString:NSLocalizedString(@"File Preview", nil)];
|
||||
else if([[resource type] isEqualToString:@"STR "] && [[resource resID] shortValue] == -16396)
|
||||
[cell setPlaceholderString:NSLocalizedString(@"Creator Information", nil)];
|
||||
else if([[resource type] isEqualToString:@"vers"] && [[resource resID] shortValue] == 1)
|
||||
[cell setPlaceholderString:NSLocalizedString(@"File Version", nil)];
|
||||
else if([[resource type] isEqualToString:@"vers"] && [[resource resID] shortValue] == 2)
|
||||
[cell setPlaceholderString:NSLocalizedString(@"Package Version", nil)];
|
||||
else [cell setPlaceholderString:NSLocalizedString(@"Untitled Resource", nil)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[cell setDrawsBackground:YES];
|
||||
[cell setBackgroundColor:[NSColor colorWithCalibratedRed:0.93 green:0.95 blue:1.0 alpha:1.0]];
|
||||
// pre-10.3, set text colour to grey and set title accordingly
|
||||
if([[resource resID] shortValue] == -16455)
|
||||
[cell setTitle:NSLocalizedString(@"Custom Icon", nil)];
|
||||
else if([[resource type] isEqualToString:@"carb"] && [[resource resID] shortValue] == 0)
|
||||
[cell setTitle:NSLocalizedString(@"Carbon Identifier", nil)];
|
||||
else if([[resource type] isEqualToString:@"pnot"] && [[resource resID] shortValue] == 0)
|
||||
[cell setTitle:NSLocalizedString(@"File Preview", nil)];
|
||||
else if([[resource type] isEqualToString:@"STR "] && [[resource resID] shortValue] == -16396)
|
||||
[cell setTitle:NSLocalizedString(@"Creator Information", nil)];
|
||||
else if([[resource type] isEqualToString:@"vers"] && [[resource resID] shortValue] == 1)
|
||||
[cell setTitle:NSLocalizedString(@"File Version", nil)];
|
||||
else if([[resource type] isEqualToString:@"vers"] && [[resource resID] shortValue] == 2)
|
||||
[cell setTitle:NSLocalizedString(@"Package Version", nil)];
|
||||
else [cell setTitle:NSLocalizedString(@"Untitled Resource", nil)];
|
||||
|
||||
// if([[outlineView selectedItems] containsObject:resource])
|
||||
// [cell setTextColor:[NSColor whiteColor]];
|
||||
// else [cell setTextColor:[NSColor grayColor]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSOutlineView (OutlineSortView)
|
||||
|
||||
- (void)swapForOutlineSortView
|
||||
// draw alternating blue/white backgrounds (if pre-10.3)
|
||||
if(NSAppKitVersionNumber < 700.0)
|
||||
{
|
||||
isa = [OutlineSortView class];
|
||||
int row = [outlineView rowForItem:item];
|
||||
if(row % 2) [cell setBackgroundColor:[NSColor colorWithCalibratedRed:0.93 green:0.95 blue:1.0 alpha:1.0]];
|
||||
else [cell setBackgroundColor:[NSColor whiteColor]];
|
||||
[cell setDrawsBackground:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation OutlineSortView
|
||||
@implementation RKOutlineView
|
||||
|
||||
/*!
|
||||
@method draggingSourceOperationMaskForLocal:
|
||||
*/
|
||||
- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)local
|
||||
{
|
||||
if(local) return NSDragOperationEvery;
|
||||
else return NSDragOperationCopy;
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)event
|
||||
{
|
||||
if( [self selectedRow] != -1 && [[event characters] isEqualToString:[NSString stringWithCString:"\r"]] )
|
||||
[self editColumn:0 row:[self selectedRow] withEvent:nil select:YES];
|
||||
int selectedRow = [self selectedRow];
|
||||
if(selectedRow != -1 && [[event characters] isEqualToString:[NSString stringWithCString:"\r"]])
|
||||
[self editColumn:0 row:selectedRow withEvent:nil select:YES];
|
||||
else if(selectedRow != -1 && [[event characters] isEqualToString:[NSString stringWithCString:"\x7F"]])
|
||||
[(ResourceDocument *)[[[self window] windowController] document] deleteSelectedResources];
|
||||
else [super keyDown:event];
|
||||
}
|
||||
|
||||
@ -162,8 +238,15 @@ int compareResourcesDescending( Resource *r1, Resource *r2, void *context )
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
@method _sendDelegateDidClickColumn:
|
||||
@pending not needed in 10.3+, use existing sort functionality
|
||||
*/
|
||||
|
||||
//- (void)_sendDelegateDidMouseDownInHeader:(int)columnIndex
|
||||
- (void)_sendDelegateDidClickColumn:(int)columnIndex
|
||||
{
|
||||
// if(NSAppKitVersionNumber < 700.0)
|
||||
{
|
||||
NSTableColumn *tableColumn = [[self tableColumns] objectAtIndex:columnIndex];
|
||||
NSImage *indicator = [self indicatorImageInTableColumn:tableColumn];
|
||||
@ -176,28 +259,22 @@ int compareResourcesDescending( Resource *r1, Resource *r2, void *context )
|
||||
[self setIndicatorImage:downArrow inTableColumn:tableColumn];
|
||||
else [self setIndicatorImage:upArrow inTableColumn:tableColumn];
|
||||
}
|
||||
else
|
||||
{
|
||||
// new column selected
|
||||
if( [self highlightedTableColumn] != nil )
|
||||
else // new column selected
|
||||
{
|
||||
// if there is an existing selection, clear it's image
|
||||
if([self highlightedTableColumn] != nil)
|
||||
[self setIndicatorImage:nil inTableColumn:[self highlightedTableColumn]];
|
||||
}
|
||||
|
||||
if( [[tableColumn identifier] isEqualToString:@"name"] || [[tableColumn identifier] isEqualToString:@"type"] )
|
||||
{
|
||||
// sort name and type columns ascending by default
|
||||
if([[tableColumn identifier] isEqualToString:@"name"] || [[tableColumn identifier] isEqualToString:@"type"])
|
||||
[self setIndicatorImage:upArrow inTableColumn:tableColumn];
|
||||
}
|
||||
else
|
||||
{
|
||||
// sort all other columns descending by default
|
||||
[self setIndicatorImage:downArrow inTableColumn:tableColumn];
|
||||
}
|
||||
else [self setIndicatorImage:downArrow inTableColumn:tableColumn];
|
||||
[self setHighlightedTableColumn:tableColumn];
|
||||
}
|
||||
[[self delegate] tableView:self didClickTableColumn:tableColumn];
|
||||
}
|
||||
// else [super _sendDelegateDidClickColumn:columnIndex];
|
||||
}
|
||||
|
||||
@end
|
@ -1,6 +1,8 @@
|
||||
#import "PasteboardDocument.h"
|
||||
#import "Resource.h"
|
||||
|
||||
extern NSString *RKResourcePboardType;
|
||||
|
||||
@implementation PasteboardDocument
|
||||
|
||||
- (id)init
|
||||
@ -15,32 +17,36 @@
|
||||
|
||||
-(void)readPasteboard:(NSString *)pbName
|
||||
{
|
||||
// this method is mostly a duplicate of -[ResourceDocument paste:] but takes a pasteboard name for an argument
|
||||
NSPasteboard *pb = [NSPasteboard pasteboardWithName:pbName];
|
||||
NSArray *types = [pb types];
|
||||
NSEnumerator *enumerator = [types objectEnumerator];
|
||||
NSString *currentType;
|
||||
NSEnumerator *enumerator = [[pb types] objectEnumerator];
|
||||
NSString *pbType;
|
||||
|
||||
// clear current pasteboard representation
|
||||
[self selectAll:nil];
|
||||
[self clear:nil];
|
||||
|
||||
// set the window's title to represent the pasteboard being shown (at some point I anticipate having several of these)
|
||||
[[self window] setTitle:pbName];
|
||||
|
||||
// disable undos during loading
|
||||
[[self undoManager] disableUndoRegistration];
|
||||
while( currentType = [enumerator nextObject] )
|
||||
|
||||
// get all types off the pasteboard
|
||||
while( pbType = [enumerator nextObject] )
|
||||
{
|
||||
// create the resource & add it to the array
|
||||
NSString *name = pbName;
|
||||
NSString *type;
|
||||
NSNumber *resID;
|
||||
NSNumber *attributes;
|
||||
NSData *data;
|
||||
Resource *resource;
|
||||
NS_DURING
|
||||
type = [currentType substringToIndex:3];
|
||||
NS_HANDLER
|
||||
type = currentType;
|
||||
NS_ENDHANDLER
|
||||
resID = [NSNumber numberWithShort:0];
|
||||
attributes = [NSNumber numberWithShort:0];
|
||||
data = [pb dataForType:type];
|
||||
resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data];
|
||||
// 'paste' any resources into pbdoc's data source
|
||||
if( [pbType isEqualToString:RKResourcePboardType] )
|
||||
[self pasteResources:[NSUnarchiver unarchiveObjectWithData:[pb dataForType:RKResourcePboardType]]];
|
||||
else
|
||||
{
|
||||
// create the faux resource & add it to the array
|
||||
Resource *resource = [Resource resourceOfType:nil andID:nil withName:pbType andAttributes:nil data:[pb dataForType:pbType]];
|
||||
[resources addObject:resource]; // array retains resource
|
||||
}
|
||||
}
|
||||
|
||||
// re-enable undos
|
||||
[[self undoManager] enableUndoRegistration];
|
||||
|
||||
[outlineView reloadData];
|
||||
|
@ -31,10 +31,3 @@ enum LaunchAction
|
||||
+ (id)sharedPrefsWindowController;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSString (BooleanSupport)
|
||||
|
||||
- (BOOL)boolValue;
|
||||
+ (NSString *)stringWithBool:(BOOL)boolean;
|
||||
|
||||
@end
|
@ -4,9 +4,7 @@
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [self initWithWindowNibName:@"PrefsWindow"];
|
||||
if( self ) [self setWindowFrameAutosaveName:@"ResKnife Preferences"];
|
||||
return self;
|
||||
return [self initWithWindowNibName:@"PrefsWindow"];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
@ -19,6 +17,7 @@
|
||||
{
|
||||
// represent current prefs in window state
|
||||
[self updatePrefs:nil];
|
||||
[[self window] center];
|
||||
|
||||
// listen out for pref changes from elsewhere
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatePrefs:) name:NSUserDefaultsDidChangeNotification object:nil];
|
||||
@ -101,26 +100,9 @@
|
||||
+ (id)sharedPrefsWindowController
|
||||
{
|
||||
static PrefsWindowController *sharedPrefsWindowController = nil;
|
||||
|
||||
if( !sharedPrefsWindowController )
|
||||
{
|
||||
sharedPrefsWindowController = [[PrefsWindowController allocWithZone:[self zone]] init];
|
||||
}
|
||||
return sharedPrefsWindowController;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSString (BooleanSupport)
|
||||
|
||||
- (BOOL)boolValue
|
||||
{
|
||||
return [self isEqualToString:@"YES"];
|
||||
}
|
||||
|
||||
+ (NSString *)stringWithBool:(BOOL)boolean
|
||||
{
|
||||
return boolean? @"YES" : @"NO";
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -1,29 +1,26 @@
|
||||
#import "RKDocumentController.h"
|
||||
#import "ApplicationDelegate.h"
|
||||
#import "OpenFileDataSource.h"
|
||||
#import "OpenPanelDelegate.h"
|
||||
|
||||
@implementation RKDocumentController
|
||||
|
||||
// because I swap the isa pointer I can't add instance variables, so use statics instead (there will only ever be one RKDocumentController)
|
||||
static id oldDelegate = nil;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if( self )
|
||||
{
|
||||
// for some reason calling -[super init] causes a new instance of self to be returned (which is not of my subclass) so to get my overridden methods called again, I have to do this...
|
||||
isa = [RKDocumentController class];
|
||||
oldDelegate = [[NSOpenPanel openPanel] delegate];
|
||||
[[NSOpenPanel openPanel] setDelegate:[[[OpenPanelDelegate alloc] init] autorelease]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (int)runModalOpenPanel:(NSOpenPanel *)openPanel forTypes:(NSArray *)extensions
|
||||
{
|
||||
[openPanel setAccessoryView:[(ApplicationDelegate *)[NSApp delegate] openAuxView]];
|
||||
return [super runModalOpenPanel:openPanel forTypes:extensions];
|
||||
// set-up open panel (this happens every time, but no harm done)
|
||||
ApplicationDelegate *appDelegate = [NSApp delegate];
|
||||
OpenPanelDelegate *openPanelDelegate = [appDelegate openPanelDelegate];
|
||||
NSView *openPanelAccessoryView = [openPanelDelegate openPanelAccessoryView];
|
||||
[openPanel setDelegate:openPanelDelegate];
|
||||
[openPanel setAccessoryView:openPanelAccessoryView];
|
||||
[openPanel setAllowsOtherFileTypes:YES];
|
||||
[openPanel setTreatsFilePackagesAsDirectories:YES];
|
||||
[openPanelAccessoryView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
|
||||
// run panel
|
||||
int button = [super runModalOpenPanel:openPanel forTypes:extensions];
|
||||
if(button == NSOKButton)
|
||||
[openPanelDelegate setReadOpenPanelForFork:YES];
|
||||
return button;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -32,13 +32,12 @@
|
||||
|
||||
@interface RKEditorRegistry : NSObject
|
||||
{
|
||||
NSMutableDictionary* typeRegistry; // Private. Use editorForType: to access this.
|
||||
@private
|
||||
NSMutableDictionary *typeRegistry;
|
||||
}
|
||||
|
||||
+(RKEditorRegistry*) mainRegistry; // There's usually only one object, and this returns or creates it.
|
||||
|
||||
+ (RKEditorRegistry *)defaultRegistry; // There's usually only one object, and this returns or creates it.
|
||||
- (IBAction)scanForPlugins:(id)sender; // Called automatically by mainRegistry.
|
||||
- (Class)editorForType:(NSString *)typeStr; // You probably want to call this.
|
||||
|
||||
|
||||
@end
|
||||
|
@ -22,131 +22,160 @@
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#import "RKEditorRegistry.h"
|
||||
#import "RKSupportResourceRegistry.h"
|
||||
#import "NSString-FSSpec.h" // for ResKnifeBoolExtensions (in wrong file)
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Globals:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
RKEditorRegistry* gRKEditorRegistryMainRegistry = nil; // Access through +mainRegistry!
|
||||
|
||||
/*!
|
||||
@class RKEditorRegistry
|
||||
@author Uli Kusterer
|
||||
@created 2003-07-31
|
||||
@description This is a registry where all our resource-editor plugins are looked
|
||||
up and entered in a list, so you can ask for the editor for a specific
|
||||
resource type and it is returned immediately. This registry reads the
|
||||
types a plugin handles from their info.plist. This is better than
|
||||
encoding the type in the plugin file name, as file names are not
|
||||
guaranteed to be on a case-sensitive file system on Mac, and this also
|
||||
allows an editor to register for several resource types.
|
||||
*/
|
||||
|
||||
@implementation RKEditorRegistry
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
mainRegistry:
|
||||
Returns the main plugin registry of this application, instantiating
|
||||
it first if there is none yet. As soon as this is instantiated, the
|
||||
plugins are loaded.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
+(RKEditorRegistry*) mainRegistry
|
||||
/*!
|
||||
@method +defaultRegistry
|
||||
@author Uli Kusterer
|
||||
@created 2003-07-31
|
||||
@updated 2003-10-28 NGS: Changed method name from +mainRegistry (so it more closly matchs +defaultCenter) and moved global var inside method, making it a static.
|
||||
@description Returns the default plugin registry of this application, instantiating it first if there is none yet. As soon as this is instantiated, the plugins are loaded.
|
||||
*/
|
||||
+ (RKEditorRegistry *)defaultRegistry
|
||||
{
|
||||
if( !gRKEditorRegistryMainRegistry )
|
||||
static RKEditorRegistry *defaultRegistry = nil;
|
||||
if(!defaultRegistry)
|
||||
{
|
||||
gRKEditorRegistryMainRegistry = [[RKEditorRegistry alloc] init];
|
||||
[gRKEditorRegistryMainRegistry scanForPlugins: gRKEditorRegistryMainRegistry];
|
||||
defaultRegistry = [[RKEditorRegistry alloc] init];
|
||||
[defaultRegistry scanForPlugins:nil];
|
||||
}
|
||||
return gRKEditorRegistryMainRegistry;
|
||||
return defaultRegistry;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
awakeFromNib:
|
||||
Makes sure that if an instance of this is instantiated from a NIB file,
|
||||
it automatically loads the plugins.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*!
|
||||
@method awakeFromNib
|
||||
@abstract Makes sure that if an instance of this is instantiated from a nib file, it automatically loads the plugins.
|
||||
@author Uli Kusterer
|
||||
@created 2003-07-31
|
||||
*/
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[self scanForPlugins: self];
|
||||
[self scanForPlugins:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
@method scanForPlugins:
|
||||
@abstract (Re)loads our list of plugins. You can use this as an action for a menu item, if you want.
|
||||
@author Uli Kusterer
|
||||
@created 2003-07-31
|
||||
@updated 2003-10-28 NGS: Updated to look for more sophisticated RKSupportedTypes key in addition to (the now deprecated) RKEditedTypes.
|
||||
@pending Use NSSearchPathForDirectoriesInDomains() or equivalent to get folder paths instead of hard coding them.
|
||||
@pending Currently, Cocoa classes can't be unloaded, which means we're
|
||||
not leaking the NSBundles we load here. However, if this one
|
||||
day shouldn't hold true anymore, we'll want to retain these
|
||||
bundles in our dictionary and do the principalClass thingie
|
||||
in editorForType: instead, which allows us to get rid of the
|
||||
class and its bundle when reloading the plugin list by simply
|
||||
relying on NSMutableDictionary to release it.
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
scanForPlugins:
|
||||
(Re)loads our list of plugins. You can use this as an action for a menu
|
||||
item, if you want.
|
||||
@description This scans the application's internal Plugins folder,
|
||||
<tt>~/Library/Application Support/ResKnife/Plugins/</tt> and
|
||||
<tt>/Library/Application Support/ResKnife/Plugins/</tt> for
|
||||
plugins that have the extension ".plugin" and implement
|
||||
<tt>initWithResource:</tt> (which means this won't get into
|
||||
the way if you want to support other kinds of plugins).</p>
|
||||
|
||||
This scans the application's internal Plugins folder,
|
||||
~/Library/Application Support/ResKnife/Plugins/ and
|
||||
/Library/Application Support/ResKnife/Plugins/ for plugins that have
|
||||
the extension ".plugin" and implement initWithResource: (which means
|
||||
this won't get into the way if you want to support other kinds of
|
||||
plugins).
|
||||
|
||||
It builds a registry of Class objects in an NSMutableDictionary, where
|
||||
the key is the resource type. If a plugin supports several resource
|
||||
types (as indicated by the RKEditedTypes key in its Info.plist), it
|
||||
will be registered for these types as well. If several plugins register
|
||||
for the same type, the last one loaded wins.
|
||||
|
||||
To instantiate an object from a plugin, see the method below.
|
||||
|
||||
TODO:
|
||||
Currently, Cocoa classes can't be unloaded, which means we're not
|
||||
leaking the NSBundles we load here. However, if this one day shouldn't
|
||||
hold true anymore, we'll want to retain these bundles in our dictionary
|
||||
and do the principalClass thingie in editorForType: instead, which
|
||||
allows us to get rid of the class and its bundle when reloading the
|
||||
plugin list by simply relying on NSMutableDictionary to release it.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
<p>It builds a registry of Class objects in an NSMutableDictionary,
|
||||
where the key is the resource type. If a plugin supports several
|
||||
resource types (as indicated by the RKEditedTypes key in it's
|
||||
Info.plist), it will be registered for these types as well.
|
||||
If several plugins register for the same type, the last one
|
||||
loaded wins.</p>
|
||||
|
||||
<p>To instantiate an object from a plugin, see <tt>editorForType:</tt>
|
||||
*/
|
||||
- (IBAction)scanForPlugins:(id)sender
|
||||
{
|
||||
// TODO: Instead of hard-coding sysPath we should use some FindFolder-like API!
|
||||
Class pluginClass;
|
||||
NSString *appSupport = @"Library/Application Support/ResKnife/Plugins/";
|
||||
NSString *appPath = [[NSBundle mainBundle] builtInPlugInsPath];
|
||||
NSString *userPath = [NSHomeDirectory() stringByAppendingPathComponent:appSupport];
|
||||
NSString *sysPath = [@"/" stringByAppendingPathComponent:appSupport];
|
||||
NSArray *paths = [NSArray arrayWithObjects:appPath, userPath, sysPath, nil];
|
||||
NSEnumerator *pathEnum = [paths objectEnumerator];
|
||||
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory, NSAllDomainsMask, YES);
|
||||
NSEnumerator *pathEnumerator = [[NSArray arrayWithObjects:appPath, userPath, sysPath, nil] objectEnumerator];
|
||||
NSString *path;
|
||||
|
||||
if( typeRegistry )
|
||||
[typeRegistry release];
|
||||
// release any existing registry to clear old values
|
||||
if(typeRegistry) [typeRegistry release];
|
||||
typeRegistry = [[NSMutableDictionary alloc] init];
|
||||
|
||||
while( path = [pathEnum nextObject] )
|
||||
// scan all paths
|
||||
while(path = [pathEnumerator nextObject])
|
||||
{
|
||||
NSEnumerator *e = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
|
||||
NSString *name;
|
||||
NSEnumerator *fileEnumerator = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
|
||||
NSString *pluginName;
|
||||
|
||||
while( name = [e nextObject] )
|
||||
// enumerate all files in this directory
|
||||
while(pluginName = [fileEnumerator nextObject])
|
||||
{
|
||||
name = [path stringByAppendingPathComponent:name];
|
||||
NSLog(@"Examining %@", name);
|
||||
if( [[name pathExtension] isEqualToString:@"plugin"] )
|
||||
{
|
||||
NSBundle *plugin = [NSBundle bundleWithPath: name];
|
||||
NSString *pluginPath = [path stringByAppendingPathComponent:pluginName];
|
||||
// NSLog(@"Examining %@", pluginPath);
|
||||
|
||||
if( pluginClass = [plugin principalClass] )
|
||||
// verify file is a plugin
|
||||
if([[pluginName pathExtension] isEqualToString:@"plugin"])
|
||||
{
|
||||
if( [pluginClass instancesRespondToSelector:@selector(initWithResource:)] )
|
||||
NSBundle *plugin = [NSBundle bundleWithPath:pluginPath];
|
||||
Class pluginClass = [plugin principalClass];
|
||||
if(plugin && pluginClass)
|
||||
{
|
||||
// NSLog(@"Principal class %@ %@ to ResKnifePluginProtocol", NSStringFromClass(pluginClass), [pluginClass conformsToProtocol:@protocol(ResKnifePluginProtocol)]? @"conforms":@"does not conform");
|
||||
|
||||
// check principal class implements ResKnifePluginProtocol
|
||||
if([pluginClass conformsToProtocol:@protocol(ResKnifePluginProtocol)])
|
||||
{
|
||||
NSArray *supportedTypes = [[plugin infoDictionary] objectForKey:@"RKSupportedTypes"];
|
||||
if(supportedTypes)
|
||||
{
|
||||
NSDictionary *typeEntry;
|
||||
NSEnumerator *typesEnumerator = [supportedTypes objectEnumerator];
|
||||
|
||||
// enumerate entries
|
||||
while(typeEntry = [typesEnumerator nextObject])
|
||||
{
|
||||
// get values for type entry
|
||||
NSString *name = [typeEntry objectForKey:@"RKTypeName"];
|
||||
NSString *role = [typeEntry objectForKey:@"RKTypeRole"];
|
||||
BOOL isDefault = [(NSString *)[typeEntry objectForKey:@"IsResKnifeDefaultForType"] boolValue];
|
||||
|
||||
// register them
|
||||
[typeRegistry setObject:pluginClass forKey:name]; // bug: very primative, doesn't use extra data
|
||||
// NSLog(@"Plug-in class %@ registered as %@%@ for type %@.", NSStringFromClass(pluginClass), isDefault? @"default ":@"", role, name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// try the old way of looking up types
|
||||
NSString *resType;
|
||||
NSArray *types = [[plugin infoDictionary] objectForKey:@"RKEditedTypes"];
|
||||
NSEnumerator *enny;
|
||||
supportedTypes = [[plugin infoDictionary] objectForKey:@"RKEditedTypes"];
|
||||
if(supportedTypes == nil)
|
||||
supportedTypes = [NSArray arrayWithObject: [[plugin infoDictionary] objectForKey:@"RKEditedType"]];
|
||||
|
||||
if( types == nil )
|
||||
types = [NSArray arrayWithObject: [[plugin infoDictionary] objectForKey:@"RKEditedType"]];
|
||||
|
||||
for( enny = [types objectEnumerator]; resType = [enny nextObject]; )
|
||||
for(enny = [supportedTypes objectEnumerator]; resType = [enny nextObject];)
|
||||
{
|
||||
[typeRegistry setObject:pluginClass forKey:resType];
|
||||
NSLog(@"Registered for type %@.",resType);
|
||||
// NSLog(@"Registered for type %@.",resType);
|
||||
}
|
||||
}
|
||||
|
||||
// load any support resources in the plug-in
|
||||
[RKSupportResourceRegistry scanForSupportResourcesInFolder:[[plugin resourcePath] stringByAppendingPathComponent:@"Support Resources"]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,10 +201,8 @@ RKEditorRegistry* gRKEditorRegistryMainRegistry = nil; // Access through +mainR
|
||||
- (Class)editorForType:(NSString *)typeStr
|
||||
{
|
||||
Class theClass = [typeRegistry objectForKey: typeStr];
|
||||
if( !theClass )
|
||||
return Nil;
|
||||
|
||||
return theClass;
|
||||
if(!theClass) return Nil;
|
||||
else return theClass;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -11,10 +11,7 @@
|
||||
|
||||
@interface RKSupportResourceRegistry : NSObject
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
+(void) scanForSupportResources: (NSDocumentController*)c;
|
||||
|
||||
|
||||
+ (void)scanForSupportResources;
|
||||
+ (void)scanForSupportResourcesInFolder:(NSString *)path;
|
||||
@end
|
||||
|
@ -1,44 +1,32 @@
|
||||
//
|
||||
// RKSupportResourceRegistry.m
|
||||
// ResKnife
|
||||
//
|
||||
// Created by Uli Kusterer on Mon Aug 18 2003.
|
||||
// Copyright (c) 2003 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKSupportResourceRegistry.h"
|
||||
|
||||
#import "NGSCategories.h"
|
||||
|
||||
@implementation RKSupportResourceRegistry
|
||||
|
||||
+(void) scanForSupportResources: (NSDocumentController*)c
|
||||
+ (void)scanForSupportResources
|
||||
{
|
||||
// TODO: Instead of hard-coding sysPath we should use some FindFolder-like API!
|
||||
NSString *appSupport = @"Library/Application Support/ResKnife/Support Resources/";
|
||||
NSString *appPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Support Resources"];
|
||||
NSString *userPath = [NSHomeDirectory() stringByAppendingPathComponent:appSupport];
|
||||
NSString *sysPath = [@"/" stringByAppendingPathComponent:appSupport];
|
||||
NSArray *paths = [NSArray arrayWithObjects:appPath, userPath, sysPath, nil];
|
||||
NSEnumerator *pathEnum = [paths objectEnumerator];
|
||||
NSString *path;
|
||||
#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
NSArray *dirsArray = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSAllDomainsMask, YES);
|
||||
dirsArray = [dirsArray arrayByMakingObjectsPerformSelector:@selector(stringByAppendingPathComponent:) withObject:@"ResKnife/Support Resources"];
|
||||
#endif
|
||||
[RKSupportResourceRegistry scanForSupportResourcesInFolder:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Support Resources"]];
|
||||
[RKSupportResourceRegistry scanForSupportResourcesInFolder:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/ResKnife/Support Resources"]];
|
||||
[RKSupportResourceRegistry scanForSupportResourcesInFolder:@"/Library/Application Support/ResKnife/Support Resources"];
|
||||
[RKSupportResourceRegistry scanForSupportResourcesInFolder:@"/Network/Library/Application Support/ResKnife/Support Resources"];
|
||||
}
|
||||
|
||||
while( path = [pathEnum nextObject] )
|
||||
+ (void)scanForSupportResourcesInFolder:(NSString *)path
|
||||
{
|
||||
NSEnumerator *e = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
|
||||
// NSLog(@"Looking for resources in %@", path);
|
||||
NSString *name;
|
||||
|
||||
NSLog(@"Looking for resources in %@", path);
|
||||
|
||||
while( name = [e nextObject] )
|
||||
NSEnumerator *enumerator = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
|
||||
while(name = [enumerator nextObject])
|
||||
{
|
||||
name = [path stringByAppendingPathComponent:name];
|
||||
NSLog(@"Examining %@", name);
|
||||
// NSLog(@"Examining %@", name);
|
||||
if([[name pathExtension] isEqualToString:@"rsrc"])
|
||||
{
|
||||
[c openDocumentWithContentsOfFile:name display:YES];
|
||||
//[[[[[c openDocumentWithContentsOfFile:name display:YES] windowControllers] objectAtIndex:0] window] orderOut: self];
|
||||
}
|
||||
}
|
||||
// FIXME: this method was deprecate in 10.4 in favour of - (id)openDocumentWithContentsOfURL:(NSURL *)absoluteURL display:(BOOL)displayDocument error:(NSError **)outError;
|
||||
[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfFile:[path stringByAppendingPathComponent:name] display:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,12 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ResKnifeResourceProtocol.h"
|
||||
#import "../Plug-Ins/ResKnifeResourceProtocol.h"
|
||||
|
||||
/*!
|
||||
@class Resource
|
||||
@author Nicholas Shanks
|
||||
@abstract Encapsulates a single resource and all associated meta-data.
|
||||
@description The Resource class fully complies with key-value coding, with the keys @"name", @"type", @"resID", @"attributes", @"data", @"dirty" and @"representedFork" available.
|
||||
*/
|
||||
|
||||
@interface Resource : NSObject <NSCopying, NSCoding, ResKnifeResourceProtocol>
|
||||
{
|
||||
@ -17,13 +24,16 @@
|
||||
// the actual data
|
||||
NSData *data;
|
||||
|
||||
NSDocument *document; // Our owner.
|
||||
// the document name for display to the user; updating this is the responsibility of the document itself
|
||||
NSString *_docName;
|
||||
}
|
||||
|
||||
// accessor methods not part of the protocol
|
||||
- (void)_setName:(NSString *)newName;
|
||||
- (void)setDirty:(BOOL)newValue;
|
||||
- (NSString *)representedFork;
|
||||
- (void)setRepresentedFork:(NSString *)forkName;
|
||||
- (void)setDocumentName:(NSString *)docName;
|
||||
|
||||
// init methods
|
||||
- (id)initWithType:(NSString *)typeValue andID:(NSNumber *)resIDValue;
|
||||
@ -35,7 +45,4 @@
|
||||
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue;
|
||||
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue data:(NSData *)dataValue;
|
||||
|
||||
-(void) setDocument: (NSDocument*)doc;
|
||||
-(NSDocument*) document; // Resource protocol guarantees this.
|
||||
|
||||
@end
|
||||
|
@ -58,13 +58,13 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
return [resource autorelease];
|
||||
}
|
||||
|
||||
+ (Resource *)getResourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue inDocument:(NSDocument *)document
|
||||
+ (Resource *)getResourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue inDocument:(NSDocument *)searchDoc
|
||||
{
|
||||
NSDocument *doc;
|
||||
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
||||
while(doc = [enumerator nextObject])
|
||||
{
|
||||
if( document == nil || document == doc )
|
||||
if(searchDoc == nil || searchDoc == doc)
|
||||
{
|
||||
// parse document for correct resource
|
||||
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue andID:resIDValue];
|
||||
@ -76,7 +76,7 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
|
||||
/* ResKnifeResourceProtocol implementation */
|
||||
|
||||
+ (NSArray *)allResourcesOfType:(NSString *)typeValue inDocument:(NSDocument *)document
|
||||
+ (NSArray *)allResourcesOfType:(NSString *)typeValue inDocument:(NSDocument *)searchDoc
|
||||
{
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
NSDocument *doc;
|
||||
@ -84,19 +84,19 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
while(doc = [enumerator nextObject])
|
||||
{
|
||||
// parse document for resources
|
||||
if( document == nil || document == doc )
|
||||
if(searchDoc == nil || searchDoc == doc)
|
||||
[array addObjectsFromArray:[[(ResourceDocument *)doc dataSource] allResourcesOfType:typeValue]];
|
||||
}
|
||||
return [NSArray arrayWithArray:array];
|
||||
}
|
||||
|
||||
+ (Resource *)resourceOfType:(NSString *)typeValue withName:(NSString *)nameValue inDocument:(NSDocument *)document
|
||||
+ (Resource *)resourceOfType:(NSString *)typeValue withName:(NSString *)nameValue inDocument:(NSDocument *)searchDoc
|
||||
{
|
||||
NSDocument *doc;
|
||||
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
||||
while(doc = [enumerator nextObject])
|
||||
{
|
||||
if( document == nil || document == doc )
|
||||
if(searchDoc == nil || searchDoc == doc)
|
||||
{
|
||||
// parse document for correct resource
|
||||
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue withName:nameValue];
|
||||
@ -106,13 +106,13 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue inDocument:(NSDocument *)document
|
||||
+ (Resource *)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue inDocument:(NSDocument *)searchDoc
|
||||
{
|
||||
NSDocument *doc;
|
||||
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
||||
while(doc = [enumerator nextObject])
|
||||
{
|
||||
if( document == nil || document == doc )
|
||||
if(searchDoc == nil || searchDoc == doc)
|
||||
{
|
||||
// parse document for correct resource
|
||||
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue andID:resIDValue];
|
||||
@ -122,6 +122,24 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
return nil;
|
||||
}
|
||||
|
||||
// should probably be in resource document, not resource, but it fits in with the above methods quite well
|
||||
+ (NSDocument *)documentForResource:(Resource *)resource
|
||||
{
|
||||
NSDocument *doc;
|
||||
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
||||
while(doc = [enumerator nextObject])
|
||||
{
|
||||
Resource *res;
|
||||
NSEnumerator *enumerator2 = [[(ResourceDocument *)doc resources] objectEnumerator];
|
||||
while(res = [enumerator2 nextObject])
|
||||
{
|
||||
if([res isEqual:resource])
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[representedFork release];
|
||||
@ -130,16 +148,18 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
[resID release];
|
||||
[attributes release];
|
||||
[data release];
|
||||
[_docName release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
Resource *copy = [[Resource alloc] initWithType:type andID:resID withName:name andAttributes:attributes data:[data copy]];
|
||||
[copy setDocumentName:_docName];
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* Accessors */
|
||||
/* accessors */
|
||||
|
||||
- (void)touch
|
||||
{
|
||||
@ -157,18 +177,15 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
|
||||
-(void) setDocument: (NSDocument*)doc
|
||||
{
|
||||
document = doc; // It owns us, so don't retain, or we could get a closed loop!
|
||||
}
|
||||
|
||||
|
||||
- (NSDocument *)document
|
||||
{
|
||||
return document;
|
||||
return [Resource documentForResource:self];
|
||||
}
|
||||
|
||||
- (void)setDocumentName:(NSString *)docName
|
||||
{
|
||||
_docName = [docName copy];
|
||||
}
|
||||
|
||||
- (NSString *)representedFork
|
||||
{
|
||||
@ -185,6 +202,14 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
return name;
|
||||
}
|
||||
|
||||
// shouldn't need this - it's used by forks to give them alternate names - should use name formatter replacement instead
|
||||
- (void)_setName:(NSString *)newName
|
||||
{
|
||||
id old = name;
|
||||
name = [newName copy];
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (void)setName:(NSString *)newName
|
||||
{
|
||||
if(![name isEqualToString:newName])
|
||||
@ -192,24 +217,22 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceNameWillChangeNotification object:self];
|
||||
|
||||
[name autorelease];
|
||||
id old = name;
|
||||
name = [newName copy];
|
||||
[old release];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceNameDidChangeNotification object:self];
|
||||
// bug: this line is causing crashes!
|
||||
// [[NSNotificationCenter defaultCenter] postNotificationName:ResourceNameDidChangeNotification object:self];
|
||||
[self setDirty:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(NSString*) nameForEditorWindow
|
||||
- (NSString *)defaultWindowTitle
|
||||
{
|
||||
if( [name length] > 0 )
|
||||
return [NSString stringWithFormat: @"%@: '%@' ID=%@ \"%@\"", [document displayName], type, resID, name];
|
||||
else
|
||||
return [NSString stringWithFormat: @"%@: '%@' ID=%@", [document displayName], type, resID];
|
||||
if([name length] > 0) return [NSString stringWithFormat: NSLocalizedString(@"%@: %@ %@ '%@'", @"default window title format with resource name"), _docName, type, resID, name];
|
||||
else return [NSString stringWithFormat: NSLocalizedString(@"%@: %@ %@", @"default window title format without resource name"), _docName, type, resID];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)type
|
||||
{
|
||||
return type;
|
||||
@ -222,10 +245,12 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceTypeWillChangeNotification object:self];
|
||||
|
||||
[type autorelease];
|
||||
id old = type;
|
||||
type = [newType copy];
|
||||
[old release];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceTypeDidChangeNotification object:self];
|
||||
// bug: this line is causing crashes!
|
||||
// [[NSNotificationCenter defaultCenter] postNotificationName:ResourceTypeDidChangeNotification object:self];
|
||||
[self setDirty:YES];
|
||||
}
|
||||
}
|
||||
@ -242,10 +267,12 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceIDWillChangeNotification object:self];
|
||||
|
||||
[resID autorelease];
|
||||
id old = resID;
|
||||
resID = [newResID copy];
|
||||
[old release];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceIDDidChangeNotification object:self];
|
||||
// bug: this line is causing crashes!
|
||||
// [[NSNotificationCenter defaultCenter] postNotificationName:ResourceIDDidChangeNotification object:self];
|
||||
[self setDirty:YES];
|
||||
}
|
||||
}
|
||||
@ -262,10 +289,12 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceAttributesWillChangeNotification object:self];
|
||||
|
||||
[attributes autorelease];
|
||||
id old = attributes;
|
||||
attributes = [newAttributes copy];
|
||||
[old release];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceAttributesDidChangeNotification object:self];
|
||||
// bug: this line is causing crashes!
|
||||
// [[NSNotificationCenter defaultCenter] postNotificationName:ResourceAttributesDidChangeNotification object:self];
|
||||
[self setDirty:YES];
|
||||
}
|
||||
}
|
||||
@ -288,8 +317,9 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDataWillChangeNotification object:self];
|
||||
|
||||
// note: this function retains, rather than copies, the supplied data
|
||||
[data autorelease];
|
||||
id old = data;
|
||||
data = [newData retain];
|
||||
[old release];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDataDidChangeNotification object:self];
|
||||
[self setDirty:YES];
|
||||
|
@ -2,6 +2,11 @@
|
||||
|
||||
@class ResourceDocument, Resource;
|
||||
|
||||
/*!
|
||||
@class ResourceDataSource
|
||||
@pending This class needs to be made KVC compliant.
|
||||
*/
|
||||
|
||||
@interface ResourceDataSource : NSObject
|
||||
{
|
||||
IBOutlet NSOutlineView *outlineView;
|
||||
@ -11,18 +16,59 @@
|
||||
NSMutableArray *resources;
|
||||
}
|
||||
|
||||
/*!
|
||||
@method window
|
||||
*/
|
||||
- (NSWindow *)window;
|
||||
|
||||
/*!
|
||||
@method resources
|
||||
*/
|
||||
- (NSArray *)resources;
|
||||
|
||||
/*!
|
||||
@method setResources:
|
||||
*/
|
||||
- (void)setResources:(NSMutableArray *)newResources;
|
||||
|
||||
/*!
|
||||
@method addResource:
|
||||
*/
|
||||
- (void)addResource:(Resource *)resource;
|
||||
|
||||
/*!
|
||||
@method removeResource:
|
||||
*/
|
||||
- (void)removeResource:(Resource *)resource;
|
||||
|
||||
/*!
|
||||
@method uniqueIDForType:
|
||||
*/
|
||||
- (NSNumber *)uniqueIDForType:(NSString *)type;
|
||||
|
||||
// accessors
|
||||
/*!
|
||||
@method defaultIDForType:
|
||||
*/
|
||||
- (NSNumber *)defaultIDForType:(NSString *)type;
|
||||
|
||||
/*!
|
||||
@method resourceOfType:andID:
|
||||
*/
|
||||
- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID;
|
||||
|
||||
/*!
|
||||
@method resourceOfType:withName:
|
||||
*/
|
||||
- (Resource *)resourceOfType:(NSString *)type withName:(NSString *)name;
|
||||
|
||||
/*!
|
||||
@method allResourcesOfType:
|
||||
*/
|
||||
- (NSArray *)allResourcesOfType:(NSString *)type;
|
||||
|
||||
/*!
|
||||
@method allResourceIDsOfType:
|
||||
*/
|
||||
- (NSArray *)allResourceIDsOfType:(NSString *)type;
|
||||
|
||||
|
||||
@end
|
||||
|
@ -1,37 +1,14 @@
|
||||
/* =============================================================================
|
||||
PROJECT: ResKnife
|
||||
FILE: ResourceDataSource.m
|
||||
|
||||
PURPOSE:
|
||||
Dedicated data source for our resource list. Shares its list of
|
||||
resources with ResourceDocument. I have no idea why Nick did this
|
||||
split, though...
|
||||
|
||||
AUTHORS: Nick Shanks, nick(at)nickshanks.com, (c) ~2001.
|
||||
M. Uli Kusterer, witness(at)zathras.de, (c) 2003.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Added storing document pointer in resource, commented.
|
||||
========================================================================== */
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Headers:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#import "ResourceDataSource.h"
|
||||
#import "ResourceDocument.h"
|
||||
#import "Resource.h"
|
||||
#import <limits.h>
|
||||
|
||||
NSString *DataSourceWillAddResourceNotification = @"DataSourceWillAddResource";
|
||||
NSString *DataSourceDidAddResourceNotification = @"DataSourceDidAddResource";
|
||||
NSString *DataSourceWillRemoveResourceNotification = @"DataSourceWillRemoveResource";
|
||||
NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResource";
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Notification names:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
NSString *DataSourceWillAddResourceNotification = @"DataSourceWillAddResourceNotification";
|
||||
NSString *DataSourceDidAddResourceNotification = @"DataSourceDidAddResourceNotification";
|
||||
NSString *DataSourceWillRemoveResourceNotification = @"DataSourceWillRemoveResourceNotification";
|
||||
NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourceNotification";
|
||||
extern NSString *RKResourcePboardType;
|
||||
|
||||
@implementation ResourceDataSource
|
||||
|
||||
@ -60,8 +37,9 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
|
||||
- (void)setResources:(NSMutableArray *)newResources
|
||||
{
|
||||
[resources autorelease];
|
||||
id old = resources;
|
||||
resources = [newResources retain];
|
||||
[old release];
|
||||
[outlineView reloadData];
|
||||
}
|
||||
|
||||
@ -71,8 +49,7 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:DataSourceWillAddResourceNotification object:dictionary];
|
||||
|
||||
// it seems very inefficient to reload the entire data source when just adding/removing one item
|
||||
// for large resource files, the data source gets reloaded hundereds of times upon load
|
||||
[resource setDocument:document];
|
||||
// for large resource files, the data source gets reloaded hundreds of times upon load
|
||||
[resources addObject:resource];
|
||||
[outlineView reloadData];
|
||||
|
||||
@ -93,21 +70,10 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
[[document undoManager] registerUndoWithTarget:self selector:@selector(addResource:) object:resource]; // NB: I hope the undo manager retains the resource, because it just got deleted :) - undo action name set by calling function
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
resourceDidChange:
|
||||
Notification from the Resource class that we're registered to. It's
|
||||
sent whenever the resource is "touch"ed.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Commented, made this "touch" the document as well.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
- (void)resourceDidChange:(NSNotification *)notification
|
||||
{
|
||||
// reload the data for the changed resource
|
||||
[outlineView reloadItem:[notification object]];
|
||||
[document updateChangeCount: NSChangeDone]; // TODO: We shouldn't need to do this, Undo should take care of this, according to the docs, but somehow the document always forgets its changes.
|
||||
}
|
||||
|
||||
/* Data source protocol implementation */
|
||||
@ -141,10 +107,11 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
#pragma unused(outlineView)
|
||||
NSString *identifier = [tableColumn identifier];
|
||||
if([identifier isEqualToString:@"resID"])
|
||||
[item takeValue:[NSNumber numberWithInt:[object intValue]] forKey:identifier];
|
||||
else [item takeValue:object forKey:identifier];
|
||||
[item setValue:[NSNumber numberWithInt:[object intValue]] forKey:identifier];
|
||||
else [item setValue:object forKey:identifier];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
/* ACCESSORS */
|
||||
|
||||
- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID
|
||||
@ -184,18 +151,17 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
return [NSArray arrayWithArray:array];
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
allResourceIDsOfType:
|
||||
Returns an NSArray full of NSNumber* objects containing the IDs of all
|
||||
resources of specified type. Used by uniqueIDForType:.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Created based on allResourcesOfType:.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*!
|
||||
@method allResourceIDsOfType:
|
||||
@discussion Returns an NSArray full of NSNumber* objects containing the IDs of all resources of specified type. Used by uniqueIDForType:.
|
||||
@updated 2003-08-01 UK Created based on allResourcesOfType:
|
||||
*/
|
||||
|
||||
- (NSArray*)allResourceIDsOfType:(NSString *)type
|
||||
{
|
||||
if(!type || [type isEqualToString:@""])
|
||||
return [NSArray array];
|
||||
|
||||
Resource *resource;
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
NSEnumerator *enumerator = [resources objectEnumerator];
|
||||
@ -207,22 +173,16 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
return [NSArray arrayWithArray:array];
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
uniqueIDForType:
|
||||
Tries to return an unused resource ID for a new resource of specified
|
||||
type. If all IDs are used up (can't really happen, because the resource
|
||||
manager can't take more than 2727 resources per file without crashing,
|
||||
but just in theory...), this will return 128 no matter whether it's
|
||||
used or not.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*!
|
||||
@method uniqueIDForType:
|
||||
@discussion Tries to return an unused resource ID for a new resource of specified type. If all IDs are used up (can't really happen, because the resource manager can't take more than 2727 resources per file without crashing, but just in theory...), this will return 128 no matter whether it's used or not.
|
||||
@updated 2003-08-01 UK: Created.
|
||||
@updated 2003-10-21 NGS: Changed to obtain initial ID from -[resource defaultIDForType:], so we can vary it on a pre-resource-type basis (like Resourcerer can)
|
||||
*/
|
||||
|
||||
- (NSNumber *)uniqueIDForType:(NSString *)type
|
||||
{
|
||||
short theID = 128;
|
||||
short theID = [[self defaultIDForType:type] shortValue];
|
||||
NSArray *array = [self allResourceIDsOfType:type];
|
||||
|
||||
if([array count] <= USHRT_MAX)
|
||||
@ -234,4 +194,54 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
return [NSNumber numberWithShort: theID];
|
||||
}
|
||||
|
||||
/*!
|
||||
@method defaultIDForType:
|
||||
@pending Method should look for resources specifying what the initial ID is for this resource type (e.g. 'vers' resources start at 0)
|
||||
*/
|
||||
|
||||
- (NSNumber *)defaultIDForType:(NSString *)type
|
||||
{
|
||||
short defaultID = 128;
|
||||
return [NSNumber numberWithShort:defaultID];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/*!
|
||||
@method outlineView:writeItems:toPasteboard:
|
||||
@abstract Called at the start of a drag event.
|
||||
*/
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pb
|
||||
{
|
||||
[pb declareTypes:[NSArray arrayWithObject:RKResourcePboardType] owner:self];
|
||||
[pb setData:[NSArchiver archivedDataWithRootObject:items] forType:RKResourcePboardType];
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@method outlineView:validateDrop:proposedItem:proposedChildIndex:
|
||||
@abstract Called when the user is hovering with a drop over our outline view.
|
||||
*/
|
||||
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)childIndex
|
||||
{
|
||||
if([info draggingSource] != outlineView)
|
||||
{
|
||||
[outlineView setDropItem:nil dropChildIndex:NSOutlineViewDropOnItemIndex];
|
||||
return NSDragOperationCopy;
|
||||
}
|
||||
else return NSDragOperationNone;
|
||||
}
|
||||
|
||||
/*!
|
||||
@method outlineView:acceptDrop:item:childIndex:
|
||||
@abstract Called when the user drops something on our outline view.
|
||||
*/
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)targetItem childIndex:(int)childIndex
|
||||
{
|
||||
NSPasteboard *pb = [info draggingPasteboard];
|
||||
if([pb availableTypeFromArray:[NSArray arrayWithObject:RKResourcePboardType]])
|
||||
[document pasteResources:[NSUnarchiver unarchiveObjectWithData:[pb dataForType:RKResourcePboardType]]];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -12,10 +12,20 @@
|
||||
NSMutableDictionary *toolbarItems;
|
||||
NSMutableArray *resources;
|
||||
HFSUniStr255 *fork; // name of fork to save to, usually empty string (data fork) or 'RESOURCE_FORK' as returned from FSGetResourceForkName()
|
||||
NSString *creator;
|
||||
NSString *type;
|
||||
NSData *creator;
|
||||
NSData *type;
|
||||
BOOL _createFork; // file had no existing resource map when opened
|
||||
}
|
||||
|
||||
- (BOOL)readFork:(NSString *)forkName asStreamFromFile:(FSRef *)fileRef;
|
||||
- (BOOL)readResourceMap:(SInt16)fileRefNum;
|
||||
- (BOOL)writeResourceMap:(SInt16)fileRefNum;
|
||||
- (BOOL)writeForkStreamsToFile:(NSString *)fileName;
|
||||
|
||||
- (IBAction)exportResources:(id)sender;
|
||||
- (void)exportResource:(Resource *)resource;
|
||||
- (void)exportPanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
|
||||
|
||||
- (void)setupToolbar:(NSWindowController *)windowController;
|
||||
|
||||
- (IBAction)showCreateResourceSheet:(id)sender;
|
||||
@ -29,9 +39,6 @@
|
||||
- (IBAction)playSound:(id)sender;
|
||||
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished;
|
||||
|
||||
-(IBAction) exportResourceToFile: (id)sender;
|
||||
-(IBAction) exportResourceToImageFile: (id)sender;
|
||||
|
||||
- (IBAction)copy:(id)sender;
|
||||
- (IBAction)paste:(id)sender;
|
||||
- (void)pasteResources:(NSArray *)pastedResources;
|
||||
@ -45,21 +52,17 @@
|
||||
- (void)resourceTypeWillChange:(NSNotification *)notification;
|
||||
- (void)resourceAttributesWillChange:(NSNotification *)notification;
|
||||
|
||||
- (BOOL)readFork:(NSString *)forkName asStreamFromFile:(NSString *)fileName;
|
||||
- (BOOL)readResourceMap:(SInt16)fileRefNum;
|
||||
- (BOOL)writeResourceMap:(SInt16)fileRefNum;
|
||||
|
||||
- (NSWindow *)mainWindow;
|
||||
- (ResourceDataSource *)dataSource;
|
||||
- (NSOutlineView *)outlineView;
|
||||
- (NSArray *)resources; // return the array as non-mutable
|
||||
|
||||
- (NSString *)creator;
|
||||
- (NSString *)type;
|
||||
- (NSData *)creator;
|
||||
- (NSData *)type;
|
||||
- (IBAction)creatorChanged:(id)sender;
|
||||
- (IBAction)typeChanged:(id)sender;
|
||||
- (void)setCreator:(NSString *)oldCreator;
|
||||
- (void)setType:(NSString *)oldType;
|
||||
- (void)setCreator:(NSString *)newCreator andType:(NSString *)newType;
|
||||
- (BOOL)setCreator:(NSData *)newCreator;
|
||||
- (BOOL)setType:(NSData *)newType;
|
||||
- (BOOL)setCreator:(NSData *)newCreator andType:(NSData *)newType;
|
||||
|
||||
@end
|
||||
|
@ -5,10 +5,9 @@
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if( self )
|
||||
{
|
||||
if(!self) return nil;
|
||||
[self setWraps:NO];
|
||||
drawImage = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -107,7 +106,6 @@
|
||||
|
||||
// get image frame
|
||||
NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
|
||||
// NSLog( "drawing name cell with bg: %@ colour: %@", [self drawsBackground]? @"YES":@"NO", [self backgroundColor] );
|
||||
if([self drawsBackground] && ![self isHighlighted] /* ![self cellAttribute:NSCellHighlighted] */)
|
||||
{
|
||||
[[self backgroundColor] set];
|
||||
|
@ -15,7 +15,7 @@
|
||||
float value = [obj floatValue];
|
||||
int power = 0;
|
||||
|
||||
while( value >= 1024 && power <= 30 )
|
||||
while( value >= 1024 /*&& power <= 30*/ )
|
||||
{
|
||||
power += 10; // 10 == KB, 20 == MB, 30+ == GB
|
||||
value /= 1024;
|
||||
|
12
Cocoa/English.lproj/AboutPanel.nib/info.nib
generated
@ -1,20 +1,20 @@
|
||||
<?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>109 310 356 240 0 0 1280 1002 </string>
|
||||
<string>147 310 356 240 0 0 1600 1002 </string>
|
||||
<key>IBFramework Version</key>
|
||||
<string>248.0</string>
|
||||
<string>446.1</string>
|
||||
<key>IBLockedObjects</key>
|
||||
<array>
|
||||
<integer>25</integer>
|
||||
</array>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>23</integer>
|
||||
<integer>21</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>5P48</string>
|
||||
<string>8L127</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
BIN
Cocoa/English.lproj/AboutPanel.nib/objects.nib
generated
30
Cocoa/English.lproj/Application.nib/classes.nib
generated
@ -1,10 +1,18 @@
|
||||
{
|
||||
IBClasses = (
|
||||
{
|
||||
ACTIONS = {showInfo = id; showPasteboard = id; showPrefs = id; };
|
||||
ACTIONS = {
|
||||
emailDeveloper = id;
|
||||
showAbout = id;
|
||||
showInfo = id;
|
||||
showPasteboard = id;
|
||||
showPrefs = id;
|
||||
visitSourceforge = id;
|
||||
visitWebsite = id;
|
||||
};
|
||||
CLASS = ApplicationDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {forkTableView = NSTableView; openAuxView = NSView; };
|
||||
OUTLETS = {openPanelDelegate = OpenPanelDelegate; };
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{
|
||||
@ -15,12 +23,12 @@
|
||||
findNext = id;
|
||||
findPrevious = id;
|
||||
findWithSelection = id;
|
||||
myAction = id;
|
||||
openResources = id;
|
||||
openResourcesAsHex = id;
|
||||
openResourcesInTemplate = id;
|
||||
playSound = id;
|
||||
revertResourceToSaved = id;
|
||||
revertResource = id;
|
||||
saveResource = id;
|
||||
scrollToSelection = id;
|
||||
showAbout = id;
|
||||
showCreateResourceSheet = id;
|
||||
@ -29,17 +37,27 @@
|
||||
showInfo = id;
|
||||
showPrefs = id;
|
||||
showSelectTemplateSheet = id;
|
||||
useIconView = id;
|
||||
useListView = id;
|
||||
};
|
||||
CLASS = FirstResponder;
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{CLASS = NSOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; },
|
||||
{
|
||||
CLASS = OpenFileDataSource;
|
||||
ACTIONS = {addFork = id; removeFork = id; };
|
||||
CLASS = OpenPanelDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {forkTableView = NSTableView; };
|
||||
OUTLETS = {
|
||||
addForkButton = NSButton;
|
||||
forkTableView = NSTableView;
|
||||
openPanelAccessoryView = NSView;
|
||||
removeForkButton = NSButton;
|
||||
};
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{CLASS = OutlineSortView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; },
|
||||
{
|
||||
ACTIONS = {
|
||||
clear = id;
|
||||
|
15
Cocoa/English.lproj/Application.nib/info.nib
generated
@ -3,22 +3,25 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBDocumentLocation</key>
|
||||
<string>264 129 383 248 0 0 1024 746 </string>
|
||||
<string>75 727 356 240 0 0 1600 1002 </string>
|
||||
<key>IBEditorPositions</key>
|
||||
<dict>
|
||||
<key>246</key>
|
||||
<string>344 386 340 222 0 0 1024 746 </string>
|
||||
<string>569 580 520 175 0 0 1600 1002 </string>
|
||||
<key>29</key>
|
||||
<string>22 682 347 44 0 0 1024 746 </string>
|
||||
<string>66 658 366 44 0 0 1600 1002 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>326.0</string>
|
||||
<string>446.1</string>
|
||||
<key>IBLockedObjects</key>
|
||||
<array/>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>1</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>246</integer>
|
||||
<integer>29</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>7A202</string>
|
||||
<string>8L127</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
BIN
Cocoa/English.lproj/Application.nib/keyedobjects.nib
generated
Normal file
BIN
Cocoa/English.lproj/Application.nib/objects.nib
generated
@ -6,7 +6,13 @@
|
||||
<string>58 46 387 357 0 0 832 602 </string>
|
||||
<key>IBFramework Version</key>
|
||||
<string>326.0</string>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>3</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>20</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>7A202</string>
|
||||
<string>7A179</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
BIN
Cocoa/English.lproj/CreateResourceSheet.nib/keyedobjects.nib
generated
Normal file
30
Cocoa/English.lproj/Credits.rtf
Normal file
@ -0,0 +1,30 @@
|
||||
{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf410
|
||||
{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
|
||||
|
||||
\f0\b\fs24 \cf0 Lead Developer:
|
||||
\f1\b0 \
|
||||
Nicholas Shanks\
|
||||
\
|
||||
|
||||
\f0\b Developers:
|
||||
\f1\b0 \
|
||||
Uli Kusterer\
|
||||
\
|
||||
|
||||
\f0\b Other Contributors:
|
||||
\f1\b0 \
|
||||
Thomas Castiglione\
|
||||
Philippe Devallois\
|
||||
Mike Margolis\
|
||||
Lane Roathe\
|
||||
Jeffrey Seibert\
|
||||
\
|
||||
|
||||
\f0\b Wanted:
|
||||
\f1\b0 \
|
||||
Plug-in editors for resource types.\
|
||||
Translations for any language.\
|
||||
Application, document & toolbar icons.\
|
||||
}
|
3
Cocoa/English.lproj/InfoWindow.nib/classes.nib
generated
@ -7,7 +7,7 @@
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{
|
||||
ACTIONS = {attributesChanged = id; nameChanged = id; };
|
||||
ACTIONS = {attributesChanged = id; };
|
||||
CLASS = InfoWindowController;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
@ -21,7 +21,6 @@
|
||||
};
|
||||
SUPERCLASS = NSWindowController;
|
||||
},
|
||||
{CLASS = NSWindowController; LANGUAGE = ObjC; SUPERCLASS = NSResponder; },
|
||||
{CLASS = SizeFormatter; LANGUAGE = ObjC; SUPERCLASS = NSNumberFormatter; }
|
||||
);
|
||||
IBVersion = 1;
|
||||
|
14
Cocoa/English.lproj/InfoWindow.nib/info.nib
generated
@ -3,16 +3,12 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBDocumentLocation</key>
|
||||
<string>142 473 384 240 0 0 1024 746 </string>
|
||||
<string>267 434 384 240 0 0 1600 1002 </string>
|
||||
<key>IBFramework Version</key>
|
||||
<string>326.0</string>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>35</integer>
|
||||
<integer>5</integer>
|
||||
<integer>50</integer>
|
||||
</array>
|
||||
<string>439.0</string>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>0</integer>
|
||||
<key>IBSystem Version</key>
|
||||
<string>7A202</string>
|
||||
<string>8I127</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
BIN
Cocoa/English.lproj/InfoWindow.nib/keyedobjects.nib
generated
Normal file
BIN
Cocoa/English.lproj/InfoWindow.nib/objects.nib
generated
@ -2,23 +2,17 @@
|
||||
IBClasses = (
|
||||
{CLASS = AttributesFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; },
|
||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||
{
|
||||
CLASS = NameFormatter;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {outlineView = NSOutlineView; };
|
||||
SUPERCLASS = NSFormatter;
|
||||
},
|
||||
{
|
||||
CLASS = OutlineViewDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
attributesFormatter = NSFormatter;
|
||||
nameFormatter = NSFormatter;
|
||||
sizeFormatter = NSNumberFormatter;
|
||||
window = NSWindow;
|
||||
};
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{CLASS = RKOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; },
|
||||
{
|
||||
CLASS = ResourceDataSource;
|
||||
LANGUAGE = ObjC;
|
||||
|
10
Cocoa/English.lproj/ResourceDocument.nib/info.nib
generated
@ -3,11 +3,15 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBDocumentLocation</key>
|
||||
<string>71 141 530 549 0 0 1600 1002 </string>
|
||||
<string>579 557 418 241 0 0 1600 1002 </string>
|
||||
<key>IBFramework Version</key>
|
||||
<string>286.0</string>
|
||||
<string>349.0</string>
|
||||
<key>IBLockedObjects</key>
|
||||
<array>
|
||||
<integer>146</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>6F21</string>
|
||||
<string>7H63</string>
|
||||
<key>IBUserGuides</key>
|
||||
<dict>
|
||||
<key>CreateResourceSheet</key>
|
||||
|
BIN
Cocoa/English.lproj/ResourceDocument.nib/objects.nib
generated
@ -0,0 +1,11 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSData (RKHexRepresentationExtensions)
|
||||
- (NSString *)hexRepresentation;
|
||||
- (NSString *)asciiRepresentation;
|
||||
- (NSString *)nonLossyAsciiRepresentation;
|
||||
@end
|
||||
|
||||
@interface NSString (RKHexConversionExtensions)
|
||||
- (NSData *)dataFromHex;
|
||||
@end
|
@ -0,0 +1,95 @@
|
||||
#import "NSData-HexRepresentation.h"
|
||||
|
||||
@implementation NSData (RKHexRepresentationExtensions)
|
||||
|
||||
- (NSString *)hexRepresentation
|
||||
{
|
||||
int currentByte = 0, dataLength = [self length];
|
||||
char buffer[dataLength*3 -1], hex1, hex2;
|
||||
char *bytes = (char *) [self bytes];
|
||||
|
||||
// return empty string if no data
|
||||
if(dataLength == 0) return [NSString string];
|
||||
|
||||
// calculate bytes
|
||||
for(currentByte = 0; currentByte < dataLength; currentByte++)
|
||||
{
|
||||
hex1 = bytes[currentByte];
|
||||
hex2 = bytes[currentByte];
|
||||
hex1 >>= 4;
|
||||
hex1 &= 0x0F;
|
||||
hex2 &= 0x0F;
|
||||
hex1 += (hex1 < 10)? 0x30 : 0x37;
|
||||
hex2 += (hex2 < 10)? 0x30 : 0x37;
|
||||
|
||||
buffer[currentByte*3] = hex1;
|
||||
buffer[currentByte*3 +1] = hex2;
|
||||
buffer[currentByte*3 +2] = 0x20;
|
||||
}
|
||||
|
||||
return [NSString stringWithCString:buffer length:(dataLength*3 -1)];
|
||||
}
|
||||
|
||||
- (NSString *)asciiRepresentation
|
||||
{
|
||||
int currentByte = 0, dataLength = [self length];
|
||||
char buffer[dataLength];
|
||||
char *bytes = (char *) [self bytes];
|
||||
|
||||
// calculate bytes
|
||||
for(currentByte = 0; currentByte < dataLength; currentByte++)
|
||||
{
|
||||
if(bytes[currentByte] >= 0x20 && bytes[currentByte] < 0x7F)
|
||||
buffer[currentByte] = bytes[currentByte];
|
||||
else buffer[currentByte] = 0x2E; // full stop
|
||||
}
|
||||
|
||||
return [NSString stringWithCString:buffer length:dataLength];
|
||||
}
|
||||
|
||||
- (NSString *)nonLossyAsciiRepresentation
|
||||
{
|
||||
int currentByte = 0, dataLength = [self length];
|
||||
char buffer[dataLength];
|
||||
char *bytes = (char *) [self bytes];
|
||||
|
||||
// calculate bytes
|
||||
for(currentByte = 0; currentByte < dataLength; currentByte++)
|
||||
{
|
||||
if(bytes[currentByte] > 0x20) // doesn't check for < 0x7F
|
||||
buffer[currentByte] = bytes[currentByte];
|
||||
// else if(bytes[currentByte] == 0x20)
|
||||
// buffer[currentByte] = 0xCA; // nbsp to stop maligned wraps - doesn't work :(
|
||||
else buffer[currentByte] = 0x2E; // full stop
|
||||
}
|
||||
|
||||
return [NSString stringWithCString:buffer length:dataLength];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSString (RKHexConversionExtensions)
|
||||
|
||||
- (NSData *)dataFromHex
|
||||
{
|
||||
unsigned long actualBytesEncoded = 0;
|
||||
unsigned long maxBytesEncoded = floor([self cStringLength] / 2.0);
|
||||
const char *bytes = [self cString];
|
||||
char *buffer = (char *) malloc(maxBytesEncoded);
|
||||
signed char hex1, hex2;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < maxBytesEncoded * 2;)
|
||||
{
|
||||
hex1 = bytes[i];
|
||||
hex2 = bytes[i+1];
|
||||
hex1 -= (hex1 < 'A')? 0x30 : ((hex1 < 'a')? 0x37 : 0x57); // 0-9 < A-Z < a-z
|
||||
hex2 -= (hex2 < 'A')? 0x30 : ((hex2 < 'a')? 0x37 : 0x57);
|
||||
if(hex1 & 0xF0 || hex2 & 0xF0) { i++; continue; } // invalid character found, move forward one byte and try again
|
||||
buffer[actualBytesEncoded++] = (hex1 << 4) + hex2;
|
||||
i += 2;
|
||||
}
|
||||
return [NSData dataWithBytesNoCopy:buffer length:actualBytesEncoded freeWhenDone:YES];
|
||||
}
|
||||
|
||||
@end
|
@ -1,6 +1,19 @@
|
||||
{
|
||||
IBClasses = (
|
||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||
{CLASS = AsciiTextView; LANGUAGE = ObjC; SUPERCLASS = HexEditorTextView; },
|
||||
{
|
||||
ACTIONS = {
|
||||
copyASCII = id;
|
||||
copyHex = id;
|
||||
pasteAsASCII = id;
|
||||
pasteAsHex = id;
|
||||
pasteAsUnicode = id;
|
||||
pasteFromHex = id;
|
||||
};
|
||||
CLASS = FirstResponder;
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{
|
||||
CLASS = HexEditorDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
@ -13,18 +26,20 @@
|
||||
};
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{CLASS = HexEditorTextView; LANGUAGE = ObjC; SUPERCLASS = NSTextView; },
|
||||
{CLASS = HexTextView; LANGUAGE = ObjC; SUPERCLASS = HexEditorTextView; },
|
||||
{
|
||||
ACTIONS = {showFind = id; };
|
||||
CLASS = HexWindowController;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
ascii = NSTextView;
|
||||
asciiScroll = NSScrollView;
|
||||
copySubmenu = NSMenu;
|
||||
hex = NSTextView;
|
||||
hexDelegate = HexEditorDelegate;
|
||||
hexScroll = NSScrollView;
|
||||
message = NSTextField;
|
||||
offset = NSTextView;
|
||||
pasteSubmenu = NSMenu;
|
||||
};
|
||||
SUPERCLASS = NSWindowController;
|
||||
}
|
||||
|
@ -3,14 +3,34 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBDocumentLocation</key>
|
||||
<string>137 230 413 304 0 0 1024 746 </string>
|
||||
<string>76 233 356 240 0 0 1600 1002 </string>
|
||||
<key>IBEditorPositions</key>
|
||||
<dict>
|
||||
<key>24</key>
|
||||
<string>239 475 202 137 0 0 1600 1002 </string>
|
||||
<key>8</key>
|
||||
<string>30 493 203 99 0 0 1600 1002 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>286.0</string>
|
||||
<string>446.1</string>
|
||||
<key>IBLockedObjects</key>
|
||||
<array>
|
||||
<integer>45</integer>
|
||||
<integer>47</integer>
|
||||
<integer>48</integer>
|
||||
<integer>42</integer>
|
||||
<integer>44</integer>
|
||||
<integer>46</integer>
|
||||
<integer>43</integer>
|
||||
</array>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>2</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>6</integer>
|
||||
<integer>24</integer>
|
||||
<integer>36</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>6F21</string>
|
||||
<string>8L127</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
BIN
Cocoa/Plug-Ins/Hex Editor/English.lproj/HexWindow.nib/keyedobjects.nib
generated
Normal file
@ -29,7 +29,7 @@
|
||||
// enable/disable boxes
|
||||
[searchSelectionOnlyBox setEnabled:([(NSTextView *)[[sender window] firstResponder] rangeForUserTextChange].length != 0)];
|
||||
|
||||
// set inital vales
|
||||
// set inital values
|
||||
if( ![searchSelectionOnlyBox isEnabled] ) [searchSelectionOnlyBox setIntValue:0];
|
||||
|
||||
// show sheet
|
||||
|
@ -2,33 +2,34 @@
|
||||
|
||||
#import "ResKnifeResourceProtocol.h"
|
||||
|
||||
@class HexWindowController;
|
||||
@class HexWindowController, HexTextView, AsciiTextView;
|
||||
|
||||
@interface HexEditorDelegate : NSObject
|
||||
{
|
||||
IBOutlet HexWindowController *controller;
|
||||
IBOutlet NSTextView *ascii;
|
||||
IBOutlet NSTextView *hex;
|
||||
IBOutlet NSTextView *offset;
|
||||
IBOutlet HexTextView *hex;
|
||||
IBOutlet AsciiTextView *ascii;
|
||||
IBOutlet NSTextField *message;
|
||||
|
||||
BOOL editedLow;
|
||||
NSRange rangeForUserTextChange;
|
||||
}
|
||||
|
||||
/* REMOVE THESE WHEN I.B. IS FIXED */
|
||||
- (void)setHex:(id)newView;
|
||||
- (void)setAscii:(id)newView;
|
||||
/* END REMOVE MARKER */
|
||||
|
||||
- (void)viewDidScroll:(NSNotification *)notification;
|
||||
- (NSString *)offsetRepresentation:(NSData *)data;
|
||||
- (NSString *)hexRepresentation:(NSData *)data;
|
||||
- (NSString *)asciiRepresentation:(NSData *)data;
|
||||
- (NSString *)hexToAscii:(NSData *)data;
|
||||
|
||||
- (NSRange)byteRangeFromHexRange:(NSRange)hexRange;
|
||||
- (NSRange)hexRangeFromByteRange:(NSRange)byteRange;
|
||||
- (NSRange)byteRangeFromAsciiRange:(NSRange)asciiRange;
|
||||
- (NSRange)asciiRangeFromByteRange:(NSRange)byteRange;
|
||||
|
||||
- (HexWindowController *)controller;
|
||||
- (NSTextView *)hex;
|
||||
- (NSTextView *)ascii;
|
||||
|
||||
- (BOOL)editedLow;
|
||||
- (void)setEditedLow:(BOOL)flag;
|
||||
- (NSRange)rangeForUserTextChange;
|
||||
|
||||
@end
|
@ -1,7 +1,6 @@
|
||||
#import "HexEditorDelegate.h"
|
||||
#import "HexWindowController.h"
|
||||
|
||||
/* Ideas, method names, and occasionally code stolen from HexEditor by Raphael Sebbe http://raphaelsebbe.multimania.com/ */
|
||||
#import "HexTextView.h"
|
||||
|
||||
@implementation HexEditorDelegate
|
||||
|
||||
@ -14,9 +13,31 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
// - MOVED TO HEX WINDOW CONTROLLER DUE TO BUG IN IB MEANING OFFSET, HEX AND ASCII AREN'T SET AT THIS TIME
|
||||
|
||||
// notify me when a view scrolls so I can update the other two
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[offset enclosingScrollView] contentView]];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[hex enclosingScrollView] contentView]];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[ascii enclosingScrollView] contentView]];
|
||||
}
|
||||
|
||||
/* REMOVE THESE WHEN I.B. IS FIXED */
|
||||
- (void)setHex:(id)newView
|
||||
{
|
||||
hex = newView;
|
||||
}
|
||||
|
||||
- (void)setAscii:(id)newView
|
||||
{
|
||||
ascii = newView;
|
||||
}
|
||||
/* END REMOVE MARKER */
|
||||
|
||||
/* data re-representation methods */
|
||||
|
||||
- (NSString *)offsetRepresentation:(NSData *)data;
|
||||
- (NSString *)offsetRepresentation:(NSData *)data
|
||||
{
|
||||
int dataLength = [data length], bytesPerRow = [controller bytesPerRow];
|
||||
int rows = (dataLength / bytesPerRow) + ((dataLength % bytesPerRow)? 1:0);
|
||||
@ -29,122 +50,30 @@
|
||||
return representation;
|
||||
}
|
||||
|
||||
- (NSString *)hexRepresentation:(NSData *)data;
|
||||
{
|
||||
int currentByte = 0, dataLength = [data length], bytesPerRow = [controller bytesPerRow];
|
||||
int rows = (dataLength / bytesPerRow) + ((dataLength % bytesPerRow)? 1:0);
|
||||
char buffer[bytesPerRow*3 +1], hex1, hex2;
|
||||
char *bytes = (char *) [data bytes];
|
||||
NSMutableString *representation = [NSMutableString string];
|
||||
int row;
|
||||
|
||||
// calculate bytes
|
||||
for( row = 0; row < rows; row++ )
|
||||
{
|
||||
int addr;
|
||||
|
||||
for( addr = 0; addr < bytesPerRow; addr++ )
|
||||
{
|
||||
if( currentByte < dataLength )
|
||||
{
|
||||
hex1 = bytes[currentByte];
|
||||
hex2 = bytes[currentByte];
|
||||
hex1 >>= 4;
|
||||
hex1 &= 0x0F;
|
||||
hex2 &= 0x0F;
|
||||
hex1 += (hex1 < 10)? 0x30 : 0x37;
|
||||
hex2 += (hex2 < 10)? 0x30 : 0x37;
|
||||
|
||||
buffer[addr*3] = hex1;
|
||||
buffer[addr*3 +1] = hex2;
|
||||
buffer[addr*3 +2] = 0x20;
|
||||
|
||||
// advance current byte
|
||||
currentByte++;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[addr*3] = 0x00;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// clear last byte on line
|
||||
buffer[bytesPerRow*3] = 0x00;
|
||||
|
||||
// append buffer to representation
|
||||
[representation appendString:[NSString stringWithCString:buffer]];
|
||||
}
|
||||
|
||||
return representation;
|
||||
}
|
||||
|
||||
- (NSString *)asciiRepresentation:(NSData *)data;
|
||||
{
|
||||
int currentByte = 0, dataLength = [data length], bytesPerRow = [controller bytesPerRow];
|
||||
int rows = (dataLength / bytesPerRow) + ((dataLength % bytesPerRow)? 1:0);
|
||||
char buffer[bytesPerRow +1];
|
||||
char *bytes = (char *) [data bytes];
|
||||
NSMutableString *representation = [NSMutableString string];
|
||||
int row;
|
||||
|
||||
// calculate bytes
|
||||
for( row = 0; row < rows; row++ )
|
||||
{
|
||||
int addr;
|
||||
|
||||
for( addr = 0; addr < bytesPerRow; addr++ )
|
||||
{
|
||||
if( currentByte < dataLength )
|
||||
{
|
||||
if( bytes[currentByte] > 0x20 && bytes[currentByte] < 0x7F )
|
||||
buffer[addr] = bytes[currentByte];
|
||||
else if( bytes[currentByte] == 0x20 )
|
||||
buffer[addr] = 0xCA; // nbsp to stop maligned wraps
|
||||
else buffer[addr] = 0x2E; // full stop
|
||||
|
||||
// advance current byte
|
||||
currentByte++;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[addr] = 0x00;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// clear last byte on line
|
||||
buffer[bytesPerRow] = 0x00;
|
||||
|
||||
// append buffer to representation
|
||||
[representation appendString:[NSString stringWithCString:buffer]];
|
||||
}
|
||||
|
||||
return representation;
|
||||
}
|
||||
|
||||
- (NSString *)hexToAscii:(NSData *)data
|
||||
{
|
||||
NSString *result;
|
||||
unsigned long bytesEncoded = ([data length] + 1) / 3;
|
||||
char *buffer = (char *) malloc( bytesEncoded ), hex1, hex2;
|
||||
int i;
|
||||
|
||||
for( 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;
|
||||
buffer[i] = (hex1 << 4) + hex2;
|
||||
}
|
||||
result = [NSString stringWithCString:buffer length:bytesEncoded];
|
||||
free( buffer );
|
||||
return result;
|
||||
}
|
||||
|
||||
/* delegation methods */
|
||||
|
||||
- (void)viewDidScroll:(NSNotification *)notification
|
||||
{
|
||||
// get object refs for increased speed
|
||||
NSClipView *object = (NSClipView *) [notification object];
|
||||
NSClipView *offsetClip = [[offset enclosingScrollView] contentView];
|
||||
NSClipView *hexClip = [[hex enclosingScrollView] contentView];
|
||||
NSClipView *asciiClip = [[ascii enclosingScrollView] contentView];
|
||||
|
||||
// remove observer to stop myself from receiving bounds changed notifications (n.b. -setPostsBoundsChangedNotifications: only suspends them temporarilly - you get a unified bounds changed notification upon enabling it again and is designed for live resizing and such, so of no use here)
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewBoundsDidChangeNotification object:nil];
|
||||
|
||||
// when a view scrolls, update the other two
|
||||
if( object != offsetClip ) [offsetClip setBoundsOrigin:[object bounds].origin];
|
||||
if( object != hexClip ) [hexClip setBoundsOrigin:[object bounds].origin];
|
||||
if( object != asciiClip ) [asciiClip setBoundsOrigin:[object bounds].origin];
|
||||
|
||||
// restore notifications
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:offsetClip];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:hexClip];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:asciiClip];
|
||||
}
|
||||
|
||||
- (NSRange)textView:(NSTextView *)textView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange
|
||||
{
|
||||
NSRange hexRange, asciiRange, byteRange = NSMakeRange(0,0);
|
||||
@ -156,16 +85,14 @@
|
||||
|
||||
if( textView == hex ) // we're selecting hexadecimal
|
||||
{
|
||||
byteRange = [self byteRangeFromHexRange:newSelectedCharRange];
|
||||
asciiRange = [self asciiRangeFromByteRange:byteRange];
|
||||
byteRange = [HexWindowController byteRangeFromHexRange:newSelectedCharRange];
|
||||
asciiRange = [HexWindowController asciiRangeFromByteRange:byteRange];
|
||||
[ascii setSelectedRange:asciiRange];
|
||||
}
|
||||
else if( textView == ascii ) // we're selecting ASCII
|
||||
{
|
||||
byteRange = [self byteRangeFromAsciiRange:newSelectedCharRange];
|
||||
hexRange = [self hexRangeFromByteRange:byteRange];
|
||||
if( hexRange.length > 0 )
|
||||
hexRange.length -= 1;
|
||||
byteRange = [HexWindowController byteRangeFromAsciiRange:newSelectedCharRange];
|
||||
hexRange = [HexWindowController hexRangeFromByteRange:byteRange];
|
||||
[hex setSelectedRange:hexRange];
|
||||
}
|
||||
|
||||
@ -178,36 +105,9 @@
|
||||
return newSelectedCharRange;
|
||||
}
|
||||
|
||||
/* range conversion methods */
|
||||
|
||||
- (NSRange)byteRangeFromHexRange:(NSRange)hexRange;
|
||||
- (HexWindowController *)controller
|
||||
{
|
||||
// valid for all window widths
|
||||
NSRange byteRange = NSMakeRange(0,0);
|
||||
byteRange.location = (hexRange.location / 3);
|
||||
byteRange.length = (hexRange.length / 3) + ((hexRange.length % 3)? 1:0);
|
||||
return byteRange;
|
||||
}
|
||||
|
||||
- (NSRange)hexRangeFromByteRange:(NSRange)byteRange;
|
||||
{
|
||||
// valid for all window widths
|
||||
NSRange hexRange = NSMakeRange(0,0);
|
||||
hexRange.location = (byteRange.location * 3);
|
||||
hexRange.length = (byteRange.length * 3);
|
||||
return hexRange;
|
||||
}
|
||||
|
||||
- (NSRange)byteRangeFromAsciiRange:(NSRange)asciiRange;
|
||||
{
|
||||
// one-to-one mapping
|
||||
return asciiRange;
|
||||
}
|
||||
|
||||
- (NSRange)asciiRangeFromByteRange:(NSRange)byteRange;
|
||||
{
|
||||
// one-to-one mapping
|
||||
return byteRange;
|
||||
return controller;
|
||||
}
|
||||
|
||||
- (NSTextView *)hex
|
||||
@ -230,4 +130,17 @@
|
||||
editedLow = flag;
|
||||
}
|
||||
|
||||
- (NSRange)rangeForUserTextChange
|
||||
{
|
||||
// if editing hex, convert hex selection to byte selection
|
||||
if( [[controller window] firstResponder] == hex )
|
||||
rangeForUserTextChange = [HexWindowController byteRangeFromHexRange:[hex rangeForUserTextChange]];
|
||||
|
||||
// if editing ascii, convert ascii selection to byte selection
|
||||
else if( [[controller window] firstResponder] == ascii )
|
||||
rangeForUserTextChange = [HexWindowController byteRangeFromAsciiRange:[ascii rangeForUserTextChange]];
|
||||
|
||||
return rangeForUserTextChange;
|
||||
}
|
||||
|
||||
@end
|
@ -2,16 +2,18 @@
|
||||
#import "HexEditorDelegate.h"
|
||||
#import "HexWindowController.h"
|
||||
|
||||
@interface HexTextView : NSTextView
|
||||
{
|
||||
}
|
||||
- (IBAction)clear:(id)sender;
|
||||
@interface HexEditorTextView : NSTextView
|
||||
- (IBAction)copyASCII:(id)sender;
|
||||
- (IBAction)copyHex:(id)sender;
|
||||
- (IBAction)pasteAsASCII:(id)sender;
|
||||
- (IBAction)pasteAsHex:(id)sender;
|
||||
- (IBAction)pasteAsUnicode:(id)sender;
|
||||
- (IBAction)clear:(id)sender;
|
||||
- (void)editData:(NSData *)data replaceBytesInRange:(NSRange)range withData:(NSData *)newData;
|
||||
@end
|
||||
|
||||
@interface NSTextView (HexTextView)
|
||||
- (void)swapForHexTextView;
|
||||
@interface HexTextView : HexEditorTextView
|
||||
@end
|
||||
|
||||
@interface AsciiTextView : HexEditorTextView
|
||||
@end
|
@ -1,88 +1,10 @@
|
||||
#import "HexTextView.h"
|
||||
#import "NSData-HexRepresentation.h"
|
||||
|
||||
@implementation HexTextView
|
||||
|
||||
- (void)drawRect:(NSRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
/* if( [[self window] isKeyWindow] && [[self window] firstResponder] == self )
|
||||
{
|
||||
NSSetFocusRingStyle( NSFocusRingOnly );
|
||||
[self setKeyboardFocusRingNeedsDisplayInRect:rect];
|
||||
}*/
|
||||
|
||||
/* [super drawRect:rect];
|
||||
if( [[self window] isKeyWindow] )
|
||||
{
|
||||
NSResponder *responder = [[self window] firstResponder];
|
||||
if( [responder isKindOfClass:[NSView class]] && [(NSView *)responder isDescendantOf:self])
|
||||
{
|
||||
NSSetFocusRingStyle( NSFocusRingOnly );
|
||||
NSRectFill( rect );
|
||||
}
|
||||
}
|
||||
[self setKeyboardFocusRingNeedsDisplayInRect:rect];*/
|
||||
}
|
||||
|
||||
- (void)setSelectedRange:(NSRange)charRange affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)flag
|
||||
{
|
||||
NSRange newRange = charRange;
|
||||
|
||||
// select whole bytes at a time (only if selecting in hex!)
|
||||
if( self == (id) [[self delegate] hex] )
|
||||
{
|
||||
// move selection offset to beginning of byte
|
||||
newRange.location -= (charRange.location % 3);
|
||||
newRange.length += (charRange.location % 3);
|
||||
|
||||
// set selection length to whole number of bytes
|
||||
if( charRange.length != 0 )
|
||||
newRange.length -= (newRange.length % 3) -2;
|
||||
else newRange.length = 0;
|
||||
|
||||
// move insertion point to next byte if needs be
|
||||
if( newRange.location == charRange.location -1 && newRange.length == 0 )
|
||||
newRange.location += 3;
|
||||
}
|
||||
|
||||
// select return character if selecting ascii
|
||||
#if( 0 ) // no longer necessary as there's a one-to-one for ascii, and the thing wraps properly instead :-)
|
||||
else if( self == (id) [[self delegate] ascii] )
|
||||
{
|
||||
// if ascii selection goes up to sixteenth byte on last line, select return character too
|
||||
if( (charRange.length + charRange.location) % 17 == 16)
|
||||
{
|
||||
// if selection is zero bytes long, move insertion point to character after return
|
||||
if( charRange.length == 0 )
|
||||
{
|
||||
// if moving back from first byte of line to previous line, skip return char
|
||||
NSRange selected = [self selectedRange];
|
||||
if( (selected.length + selected.location) % 17 == 0 )
|
||||
newRange.location -= 1;
|
||||
else newRange.location += 1;
|
||||
}
|
||||
else newRange.length += 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// call the superclass to update the selection
|
||||
[super setSelectedRange:newRange affinity:affinity stillSelecting:NO];
|
||||
}
|
||||
@implementation HexEditorTextView
|
||||
|
||||
/* NSText overrides */
|
||||
|
||||
- (BOOL)validateMenuItem:(NSMenuItem *)item
|
||||
{
|
||||
// paste submenu
|
||||
if( [item action] == @selector(paste:) )
|
||||
{
|
||||
NSMenu *editMenu = [[item menu] supermenu];
|
||||
[[editMenu itemAtIndex:[editMenu indexOfItemWithSubmenu:[item menu]]] setEnabled:[super validateMenuItem:item]];
|
||||
}
|
||||
return [super validateMenuItem:item];
|
||||
}
|
||||
|
||||
- (IBAction)cut:(id)sender
|
||||
{
|
||||
[self copy:sender];
|
||||
@ -91,110 +13,84 @@
|
||||
|
||||
- (IBAction)copy:(id)sender
|
||||
{
|
||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
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:[[(HexWindowController *)[[self window] windowController] data] subdataWithRange:selection] forType:NSStringPboardType];
|
||||
}
|
||||
|
||||
[pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
|
||||
[pb setData:[[[[self window] windowController] data] subdataWithRange:byteSelection] forType:NSStringPboardType];
|
||||
- (IBAction)copyASCII:(id)sender
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)copyHex:(id)sender
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (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)?
|
||||
|
||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
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;
|
||||
}
|
||||
|
||||
// pastes data as it is on the clipboard
|
||||
if([pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]])
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:[pb dataForType:NSStringPboardType]];
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:selection withData:[pb dataForType:NSStringPboardType]];
|
||||
}
|
||||
|
||||
- (IBAction)pasteAsASCII:(id)sender
|
||||
{
|
||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
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;
|
||||
}
|
||||
|
||||
if( [pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]] )
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:[pb dataForType:NSStringPboardType]];
|
||||
}
|
||||
|
||||
- (IBAction)pasteAsHex:(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;
|
||||
}
|
||||
|
||||
// converts whatever string encoding is on the clipboard to the default C string encoding, then pastes
|
||||
if([pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]])
|
||||
{
|
||||
NSString *hexString = [[self delegate] hexRepresentation:[pb dataForType:NSStringPboardType]];
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:[NSData dataWithBytes:[hexString cString] length:[hexString cStringLength]]];
|
||||
NSData *asciiData = [[pb stringForType:NSStringPboardType] dataUsingEncoding:[NSString defaultCStringEncoding] allowLossyConversion:YES];
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:selection withData:asciiData];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)pasteAsUnicode:(id)sender
|
||||
{
|
||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
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;
|
||||
}
|
||||
|
||||
// converts whatever string encoding is on the clipboard to Unicode, strips off the byte order mark, then pastes
|
||||
if([pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]])
|
||||
{
|
||||
NSData *unicodeData = [[NSString stringWithUTF8String:[[pb dataForType:NSStringPboardType] bytes]] dataUsingEncoding:NSUnicodeStringEncoding];
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:unicodeData];
|
||||
NSMutableData *unicodeData = [[[pb stringForType:NSStringPboardType] dataUsingEncoding:NSUnicodeStringEncoding] mutableCopy];
|
||||
if(*((unsigned short *)[unicodeData mutableBytes]) == 0xFEFF || *((unsigned short *)[unicodeData mutableBytes]) == 0xFFFE)
|
||||
[unicodeData replaceBytesInRange:NSMakeRange(0,2) withBytes:NULL length:0];
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:selection withData:unicodeData];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)pasteAsHex:(id)sender
|
||||
{
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
||||
|
||||
// converts whatever data is on the clipboard to a hex representation of that data, then pastes
|
||||
if([pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]])
|
||||
{
|
||||
NSData *hexData = [[[pb dataForType:NSStringPboardType] hexRepresentation] dataUsingEncoding:[NSString defaultCStringEncoding] allowLossyConversion:YES];
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:selection withData:hexData];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)pasteFromHex:(id)sender
|
||||
{
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
||||
|
||||
// converts hex data present on the clipboard to the bytes they represent, then pastes
|
||||
if([pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]])
|
||||
{
|
||||
NSData *binaryData = [[pb stringForType:NSStringPboardType] dataFromHex];
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:selection withData:binaryData];
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,20 +108,13 @@
|
||||
|
||||
/* Dragging routines */
|
||||
|
||||
- (unsigned int)_insertionGlyphIndexForDrag:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
unsigned int charIndex = [super _insertionGlyphIndexForDrag:sender];
|
||||
if( self == [[self delegate] hex] )
|
||||
charIndex -= charIndex % 3;
|
||||
return charIndex;
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
|
||||
{
|
||||
return NSDragOperationNone;
|
||||
/* if(isLocal) return NSDragOperationEvery;
|
||||
else return NSDragOperationCopy;
|
||||
*/ return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric;
|
||||
}
|
||||
return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric;
|
||||
*/}
|
||||
|
||||
static NSRange draggedRange;
|
||||
|
||||
@ -236,7 +125,7 @@ static NSRange draggedRange;
|
||||
|
||||
- (void)draggedImage:(NSImage *)image endedAt:(NSPoint)point operation:(NSDragOperation)operation
|
||||
{
|
||||
/* if( operation == NSDragOperationMove )
|
||||
if(operation == NSDragOperationMove)
|
||||
{
|
||||
NSRange selection = [self rangeForUserTextChange];
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:draggedRange withData:[NSData data]];
|
||||
@ -247,7 +136,7 @@ static NSRange draggedRange;
|
||||
if(selection.location > draggedRange.location)
|
||||
selection.location -= draggedRange.length;
|
||||
[self setSelectedRange:selection];
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
|
||||
@ -263,18 +152,18 @@ static NSRange draggedRange;
|
||||
// get the insertion point location
|
||||
NSPasteboard *pb = [sender draggingPasteboard];
|
||||
NSData *pastedData = [pb dataForType:NSStringPboardType];
|
||||
int charIndex = [self _insertionGlyphIndexForDrag:sender];
|
||||
unsigned int charIndex = (unsigned int) [self _insertionGlyphIndexForDrag:sender];
|
||||
NSRange selection;
|
||||
|
||||
// convert hex string to data
|
||||
if([sender draggingSource] == [[self delegate] hex])
|
||||
pastedData = [[[self delegate] hexToAscii:pastedData] dataUsingEncoding:NSASCIIStringEncoding];
|
||||
pastedData = [[[[NSString alloc] initWithData:pastedData encoding:[NSString defaultCStringEncoding]] autorelease] dataFromHex];
|
||||
|
||||
if([sender draggingSource] == [[self delegate] hex] || [sender draggingSource] == [[self delegate] ascii])
|
||||
// if(operation == NSDragOperationMove)
|
||||
{
|
||||
NSRange deleteRange = draggedRange;
|
||||
if( self == [[self delegate] hex] )
|
||||
if(self == (id) [[self delegate] hex])
|
||||
{
|
||||
deleteRange.location /= 3;
|
||||
deleteRange.length += 1;
|
||||
@ -290,7 +179,7 @@ static NSRange draggedRange;
|
||||
}
|
||||
|
||||
// insert data at insertion point
|
||||
if( self == [[self delegate] hex] ) charIndex /= 3;
|
||||
if(self == (id) [[self delegate] hex]) charIndex /= 3;
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:NSMakeRange(charIndex,0) withData:pastedData];
|
||||
|
||||
// set the new selection/insertion point
|
||||
@ -311,21 +200,10 @@ static NSRange draggedRange;
|
||||
|
||||
- (void)insertText:(NSString *)string
|
||||
{
|
||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
NSMutableData *data = [[[[self window] windowController] data] mutableCopy];
|
||||
NSData *replaceData = [NSData dataWithBytes:[string cString] length:[string cStringLength]];
|
||||
|
||||
// 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( @"Inserting text into illegal object: %@", self );
|
||||
return;
|
||||
}
|
||||
|
||||
if(self == (id) [[self delegate] hex])
|
||||
{
|
||||
int i;
|
||||
@ -338,12 +216,19 @@ static NSRange draggedRange;
|
||||
else if(typedChar >= 0x61 && typedChar <= 0x66) typedChar -= 0x57; // a to f
|
||||
else return;
|
||||
|
||||
if( [[self delegate] editedLow] ) // edited low bits already
|
||||
if(![[self delegate] editedLow]) // editing low bits
|
||||
{
|
||||
// put typed char into low bits
|
||||
typedChar &= 0x0F;
|
||||
replaceData = [NSData dataWithBytes:&typedChar length:1];
|
||||
[[self delegate] setEditedLow:YES];
|
||||
}
|
||||
else // edited low bits already
|
||||
{
|
||||
// select & retrieve old byte so it gets replaced
|
||||
char prevByte;
|
||||
byteSelection = NSMakeRange(byteSelection.location -1, 1);
|
||||
[data getBytes:&prevByte range:byteSelection];
|
||||
selection = NSMakeRange(selection.location -1, 1);
|
||||
[data getBytes:&prevByte range:selection];
|
||||
|
||||
// shift typed char into high bits and add new low char
|
||||
prevByte <<= 4; // store high bit
|
||||
@ -351,89 +236,61 @@ static NSRange draggedRange;
|
||||
replaceData = [NSData dataWithBytes:&prevByte length:1];
|
||||
[[self delegate] setEditedLow:NO];
|
||||
}
|
||||
else // editing low bits
|
||||
{
|
||||
// put typed char into low bits
|
||||
typedChar &= 0x0F;
|
||||
replaceData = [NSData dataWithBytes:&typedChar length:1];
|
||||
[[self delegate] setEditedLow:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replace bytes (updates views implicitly, records an undo)
|
||||
[self editData:data replaceBytesInRange:byteSelection withData:replaceData];
|
||||
[self editData:data replaceBytesInRange:selection withData:replaceData];
|
||||
[data release];
|
||||
|
||||
// set the new selection/insertion point
|
||||
byteSelection.location++;
|
||||
byteSelection.length = 0;
|
||||
if( self == (id) [[self delegate] hex] )
|
||||
selection = [[self delegate] hexRangeFromByteRange:byteSelection];
|
||||
else if( self == (id) [[self delegate] ascii] )
|
||||
selection = [[self delegate] asciiRangeFromByteRange:byteSelection];
|
||||
// set the new selection (insertion point)
|
||||
selection.location++;
|
||||
selection.length = 0;
|
||||
if(self == (id) [[self delegate] hex]) selection = [HexWindowController hexRangeFromByteRange:selection];
|
||||
if(self == (id) [[self delegate] ascii]) selection = [HexWindowController asciiRangeFromByteRange:selection];
|
||||
[self setSelectedRange:selection];
|
||||
}
|
||||
|
||||
- (IBAction)deleteBackward:(id)sender
|
||||
{
|
||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
NSMutableData *data = [[[[self window] windowController] data] mutableCopy];
|
||||
|
||||
// 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( @"Inserting text into illegal object: %@", self );
|
||||
return;
|
||||
}
|
||||
|
||||
// adjust selection if is insertion point
|
||||
if( byteSelection.length == 0 && selection.location > 0 )
|
||||
if(selection.length == 0 && selection.location > 0)
|
||||
{
|
||||
byteSelection.location -= 1;
|
||||
byteSelection.length = 1;
|
||||
selection.location -= 1;
|
||||
selection.length = 1;
|
||||
}
|
||||
|
||||
// replace bytes (updates views implicitly)
|
||||
[self editData:data replaceBytesInRange:byteSelection withData:[NSData data]];
|
||||
[self editData:data replaceBytesInRange:selection withData:[NSData data]];
|
||||
[data release];
|
||||
|
||||
// set the new selection/insertion point
|
||||
if( selection.length == 0 )
|
||||
// set the new selection (insertion point)
|
||||
if(selection.length == 0 && selection.location > 0)
|
||||
selection.location -= 1;
|
||||
else selection.length = 0;
|
||||
if(self == (id) [[self delegate] hex]) selection = [HexWindowController hexRangeFromByteRange:selection];
|
||||
if(self == (id) [[self delegate] ascii]) selection = [HexWindowController asciiRangeFromByteRange:selection];
|
||||
[self setSelectedRange:selection];
|
||||
}
|
||||
|
||||
- (IBAction)deleteForward:(id)sender
|
||||
{
|
||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
||||
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||
NSMutableData *data = [[[[self window] windowController] data] mutableCopy];
|
||||
|
||||
// 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( @"Inserting text into illegal object: %@", self );
|
||||
return;
|
||||
}
|
||||
|
||||
// adjust selection if is insertion point
|
||||
if( byteSelection.length == 0 && selection.location < [[self string] length] -1 )
|
||||
byteSelection.length = 1;
|
||||
if(selection.length == 0 && [self rangeForUserTextChange].location < [[self string] length] -1)
|
||||
selection.length = 1;
|
||||
|
||||
// replace bytes (updates views implicitly)
|
||||
[self editData:data replaceBytesInRange:byteSelection withData:[NSData data]];
|
||||
[self editData:data replaceBytesInRange:selection withData:[NSData data]];
|
||||
[data release];
|
||||
|
||||
// set the new selection/insertion point
|
||||
selection = [self rangeForUserTextChange];
|
||||
selection.length = 0;
|
||||
[self setSelectedRange:selection];
|
||||
}
|
||||
@ -458,6 +315,11 @@ static NSRange draggedRange;
|
||||
[self transpose:sender];
|
||||
}
|
||||
|
||||
- (void)setSelectedRange:(NSRange)charRange affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag
|
||||
{
|
||||
[super setSelectedRange:charRange affinity:affinity stillSelecting:NO];
|
||||
}
|
||||
|
||||
- (void)editData:(NSData *)data replaceBytesInRange:(NSRange)range withData:(NSData *)newBytes
|
||||
{
|
||||
// save data we're about to replace so we can restore it in an undo
|
||||
@ -469,7 +331,7 @@ static NSRange draggedRange;
|
||||
BOOL closeUndoGroup = NO;
|
||||
id undoStack = nil; // object of class _NSUndoStack
|
||||
if(![[[self window] undoManager] isUndoing])
|
||||
undoStack = [[[self window] undoManager] _undoStack];
|
||||
undoStack = (id) [[[self window] undoManager] _undoStack];
|
||||
|
||||
if(undoStack && (int)[undoStack count] > 0 && [[[self window] undoManager] groupingLevel] == 0)
|
||||
{
|
||||
@ -481,23 +343,162 @@ static NSRange draggedRange;
|
||||
[newData replaceBytesInRange:range withBytes:[newBytes bytes] length:[newBytes length]];
|
||||
[[(HexWindowController *)[[self window] windowController] resource] setData:newData];
|
||||
[self setSelectedRange:NSMakeRange(range.location + [newBytes length], 0)];
|
||||
// [[self window] setDocumentEdited:YES]; // moved to window controller's -resourceDataDidChange: notification method
|
||||
|
||||
// record undo with new data object
|
||||
[[[[self window] undoManager] prepareWithInvocationTarget:self] editData:newData replaceBytesInRange:newRange withData:oldBytes];
|
||||
[[[self window] undoManager] setActionName:NSLocalizedString(@"Typing", nil)];
|
||||
if(closeUndoGroup)
|
||||
[[[self window] undoManager] endUndoGrouping];
|
||||
// NSLog( @"%@", undoStack );
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSTextView (HexTextView)
|
||||
@implementation HexTextView
|
||||
|
||||
- (void)swapForHexTextView
|
||||
/*!
|
||||
@method selectionRangeForProposedRange:granularity:
|
||||
@abstract Adjusts the selection for insertion point and byte-selection
|
||||
@author Nicholas Shanks
|
||||
@created 2003-11-10
|
||||
*/
|
||||
|
||||
- (NSRange)selectionRangeForProposedRange:(NSRange)proposedCharRange granularity:(NSSelectionGranularity)granularity
|
||||
{
|
||||
isa = [HexTextView class];
|
||||
NSRange newRange = proposedCharRange;
|
||||
|
||||
if(newRange.length == 0)
|
||||
{
|
||||
// set insertion point location
|
||||
if(newRange.location % 3 == 1) newRange.location--;
|
||||
if(newRange.location % 3 == 2) newRange.location++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// select whole bytes at a time - bug: this doesn't quite work when selecting forwards one byte with the mouse
|
||||
granularity = NSSelectByWord;
|
||||
newRange.location -= (proposedCharRange.location % 3);
|
||||
newRange.length += (proposedCharRange.location % 3);
|
||||
|
||||
// set selection length to whole number of bytes
|
||||
if(newRange.length > 0)
|
||||
{
|
||||
if(newRange.length % 3 == 0) newRange.length--;
|
||||
if(newRange.length % 3 == 1) newRange.length++;
|
||||
}
|
||||
}
|
||||
|
||||
return [super selectionRangeForProposedRange:newRange granularity:granularity];
|
||||
}
|
||||
// also, lots of subclasser pasteboard support better to use than overriding copy: and paste:? see NSTextView.h
|
||||
|
||||
- (void)setSelectedRange:(NSRange)newRange affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag
|
||||
{
|
||||
if(newRange.length == 0 && stillSelectingFlag == NO)
|
||||
{
|
||||
// moving insertion point
|
||||
if(newRange.location % 3 == 1) newRange.location += 2;
|
||||
if(newRange.location % 3 == 2) newRange.location -= 2;
|
||||
}
|
||||
else if(stillSelectingFlag == NO && [[self window] firstResponder] == self)
|
||||
{
|
||||
NSRange oldRange = [self rangeForUserTextChange];
|
||||
|
||||
// selecting forwards
|
||||
if(oldRange.location == newRange.location && oldRange.length != newRange.length)
|
||||
// if(affinity == NSSelectionAffinityDownstream)
|
||||
{
|
||||
// selecting first byte
|
||||
if(newRange.location % 3 == 0 && newRange.length == 1 && oldRange.length < newRange.length)
|
||||
newRange.length += 1;
|
||||
// deselecting first byte
|
||||
if(newRange.location % 3 == 0 && newRange.length == 1 && oldRange.length > newRange.length)
|
||||
newRange.length = 0;
|
||||
// extending selection
|
||||
else if(newRange.location % 3 == 0 && newRange.length % 3 == 0) newRange.length += 2;
|
||||
|
||||
// reducing selection
|
||||
else if(newRange.location % 3 == 0 && newRange.length % 3 == 1) newRange.length -= 2;
|
||||
}
|
||||
|
||||
// reducing forwards selection spanning multiple rows past start point
|
||||
else if(newRange.location + newRange.length == oldRange.location && newRange.length % 3 == 1 && oldRange.length > 0)
|
||||
{
|
||||
// example: 00 00 00 00 00 00 FF FF => 00 00 00|FF FF FF 00 00
|
||||
// FF FF FF|00 00 00 00 00 => 00 00 00 00 00 00 00 00
|
||||
|
||||
newRange.location += 1;
|
||||
newRange.length -= 2;
|
||||
}
|
||||
|
||||
// inverse of above
|
||||
else if(oldRange.location + oldRange.length == newRange.location && newRange.length % 3 == 0 && oldRange.length > 0)
|
||||
{
|
||||
// example: 00 00 00|FF FF FF 00 00 => 00 00 00 00 00 00 FF FF
|
||||
// 00 00 00 00 00 00 00 00 => FF FF FF|00 00 00 00 00
|
||||
|
||||
newRange.location += 1;
|
||||
newRange.length -= 1;
|
||||
}
|
||||
|
||||
// reducing backwards selection spanning multiple rows past start point
|
||||
else if(oldRange.location + oldRange.length == newRange.location && newRange.length % 3 == 1 && oldRange.length > 0)
|
||||
{
|
||||
// example: 00 00 00 00 00 00|FF FF => 00 00 00 00 00 00 00 00
|
||||
// FF FF FF 00 00 00 00 00 => 00 00 00 FF FF FF|00 00
|
||||
|
||||
newRange.location += 1;
|
||||
newRange.length -= 2;
|
||||
}
|
||||
|
||||
// inverse of above
|
||||
else if(newRange.location + newRange.length == oldRange.location && newRange.length % 3 == 0 && oldRange.length > 0)
|
||||
{
|
||||
// example: 00 00 00 00 00 00 00 00 => 00 00 00 00 00 00|FF FF
|
||||
// 00 00 00 FF FF FF|00 00 => FF FF FF 00 00 00 00 00
|
||||
|
||||
newRange.location += 1;
|
||||
newRange.length -= 2;
|
||||
}
|
||||
|
||||
// selecting backwards
|
||||
else if(oldRange.location != newRange.location && oldRange.length != newRange.length)
|
||||
// else if(affinity == NSSelectionAffinityDownstream)
|
||||
{
|
||||
// selecting first byte
|
||||
if(newRange.location % 3 == 2 && newRange.length == 1) { newRange.location -= 2;
|
||||
newRange.length += 1; }
|
||||
// deselecting first byte
|
||||
else if(newRange.location % 3 == 1 && newRange.length == 1) { newRange.location += 2;
|
||||
newRange.length = 0; }
|
||||
// extending selection
|
||||
else if(newRange.location % 3 == 2 && newRange.length % 3 == 0) { newRange.location -= 2;
|
||||
newRange.length += 2; }
|
||||
// reducing selection
|
||||
else if(newRange.location % 3 == 1 && newRange.length % 3 == 1) { newRange.location += 2;
|
||||
newRange.length -= 2; }
|
||||
}
|
||||
}
|
||||
|
||||
[super setSelectedRange:newRange affinity:affinity stillSelecting:stillSelectingFlag];
|
||||
}
|
||||
|
||||
/*!
|
||||
@method selectionRangeForProposedRange:granularity:
|
||||
@abstract Puts insertion pointer between bytes during drag operation
|
||||
@author Nicholas Shanks
|
||||
@updated 2003-11-10 NGS: Changed algorithm.
|
||||
*/
|
||||
|
||||
- (unsigned int)_insertionGlyphIndexForDrag:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
unsigned int glyphIndex = (unsigned int) [super _insertionGlyphIndexForDrag:sender];
|
||||
if(glyphIndex % 3 == 1) glyphIndex--;
|
||||
if(glyphIndex % 3 == 2) glyphIndex++;
|
||||
return glyphIndex;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation AsciiTextView
|
||||
|
||||
@end
|
||||
|
@ -8,22 +8,31 @@
|
||||
#define kWindowStepWidthPerChar 28
|
||||
#define kWindowStepCharsPerStep 1
|
||||
|
||||
/*!
|
||||
@class HexWindowController
|
||||
@author Nicholas Shanks
|
||||
@pending Add a category to NSString to convert from hex-formatted strings to NSData objects.
|
||||
*/
|
||||
|
||||
/* Based on HexEdit by Bill Bumgardner, Lane Roath & myself: http://hexedit.sourceforge.net/ */
|
||||
/* Some ideas, method names, and occasionally code stolen from HexEditor by Raphael Sebbe: http://raphaelsebbe.multimania.com/ */
|
||||
|
||||
@interface HexWindowController : NSWindowController <ResKnifePluginProtocol>
|
||||
{
|
||||
IBOutlet HexEditorDelegate *hexDelegate;
|
||||
IBOutlet NSScrollView *asciiScroll;
|
||||
IBOutlet NSScrollView *hexScroll;
|
||||
IBOutlet NSTextView *ascii;
|
||||
IBOutlet NSTextView *hex;
|
||||
IBOutlet NSTextView *offset;
|
||||
IBOutlet NSTextField *message;
|
||||
IBOutlet NSTextView *offset; // these four should be phased out whenever possible
|
||||
IBOutlet HexTextView *hex; // these four should be phased out whenever possible
|
||||
IBOutlet AsciiTextView *ascii; // these four should be phased out whenever possible
|
||||
IBOutlet NSTextField *message; // these four should be phased out whenever possible
|
||||
IBOutlet NSMenu *copySubmenu;
|
||||
IBOutlet NSMenu *pasteSubmenu;
|
||||
|
||||
NSUndoManager *undoManager;
|
||||
id <ResKnifeResourceProtocol> resource;
|
||||
id <ResKnifeResourceProtocol> backup;
|
||||
|
||||
BOOL liveEdit;
|
||||
int bytesPerRow;
|
||||
NSUndoManager *undoManager;
|
||||
}
|
||||
|
||||
// conform to the ResKnifePluginProtocol with the inclusion of these methods
|
||||
@ -34,11 +43,10 @@
|
||||
|
||||
// save sheet methods
|
||||
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
|
||||
- (void)saveResource;
|
||||
- (void)revertResource;
|
||||
- (IBAction)saveResource:(id)sender;
|
||||
- (IBAction)revertResource:(id)sender;
|
||||
|
||||
// normal methods
|
||||
- (void)viewDidScroll:(NSNotification *)notification;
|
||||
- (void)resourceNameDidChange:(NSNotification *)notification;
|
||||
- (void)resourceDataDidChange:(NSNotification *)notification;
|
||||
- (void)resourceWasSaved:(NSNotification *)notification;
|
||||
@ -48,5 +56,13 @@
|
||||
- (id)resource;
|
||||
- (NSData *)data;
|
||||
- (int)bytesPerRow;
|
||||
- (NSMenu *)copySubmenu;
|
||||
- (NSMenu *)pasteSubmenu;
|
||||
|
||||
// bug: these should be functions not class member methods
|
||||
+ (NSRange)byteRangeFromHexRange:(NSRange)hexRange;
|
||||
+ (NSRange)hexRangeFromByteRange:(NSRange)byteRange;
|
||||
+ (NSRange)byteRangeFromAsciiRange:(NSRange)asciiRange;
|
||||
+ (NSRange)asciiRangeFromByteRange:(NSRange)byteRange;
|
||||
|
||||
@end
|
||||
|
@ -1,6 +1,7 @@
|
||||
#import "HexWindowController.h"
|
||||
#import "HexTextView.h"
|
||||
#import "FindSheetController.h"
|
||||
#import "NSData-HexRepresentation.h"
|
||||
|
||||
/*
|
||||
OSStatus Plug_InitInstance(Plug_PlugInRef plug, Plug_ResourceRef resource)
|
||||
@ -23,35 +24,33 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
- (id)initWithResource:(id)newResource
|
||||
{
|
||||
self = [self initWithWindowNibName:@"HexWindow"];
|
||||
if( !self ) return self;
|
||||
if(!self) return nil;
|
||||
|
||||
// one instance of your principal class will be created for every resource the user wants to edit (similar to Windows apps)
|
||||
undoManager = [[NSUndoManager alloc] init];
|
||||
liveEdit = NO;
|
||||
if(liveEdit)
|
||||
{
|
||||
resource = [newResource retain];
|
||||
backup = [newResource copy];
|
||||
resource = [newResource retain]; // resource to work on and monitor for external changes
|
||||
backup = [newResource copy]; // for reverting only
|
||||
}
|
||||
else
|
||||
{
|
||||
resource = [newResource copy];
|
||||
backup = [newResource retain];
|
||||
resource = [newResource copy]; // resource to work on
|
||||
backup = [newResource retain]; // actual resource to change when saving data and monitor for external changes
|
||||
}
|
||||
bytesPerRow = 16;
|
||||
|
||||
// load the window from the nib file and set it's title
|
||||
[self window]; // implicitly loads nib
|
||||
[[self window] setTitle:[resource nameForEditorWindow]];
|
||||
|
||||
// load the window from the nib file
|
||||
[self window];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[(id)resource autorelease];
|
||||
[undoManager release];
|
||||
[(id)resource release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@ -59,68 +58,86 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
{
|
||||
[super windowDidLoad];
|
||||
|
||||
// swap text views to instances of my class instead
|
||||
[offset swapForHexTextView];
|
||||
[hex swapForHexTextView];
|
||||
[ascii swapForHexTextView];
|
||||
|
||||
// turn off the background for the offset column (IB is broken when it comes to this)
|
||||
{
|
||||
// set up tab, shift-tab and enter behaviour (cannot set these in IB at the moment)
|
||||
[hex setFieldEditor:YES];
|
||||
[ascii setFieldEditor:YES];
|
||||
[offset setDrawsBackground:NO];
|
||||
[[offset enclosingScrollView] setDrawsBackground:NO];
|
||||
|
||||
// set up tab, shift-tab and enter behaviour
|
||||
[hex setFieldEditor:YES];
|
||||
[ascii setFieldEditor:YES];
|
||||
// IB fonts get ignored for some reason
|
||||
NSFont *courier = [[NSFontManager sharedFontManager] fontWithFamily:@"Courier" traits:0 weight:5 size:12.0];
|
||||
[hex setFont:courier];
|
||||
[ascii setFont:courier];
|
||||
[offset setFont:courier];
|
||||
|
||||
// from HexEditorDelegate, here until bug is fixed
|
||||
[[NSNotificationCenter defaultCenter] addObserver:hexDelegate selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[offset enclosingScrollView] contentView]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:hexDelegate selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[hex enclosingScrollView] contentView]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:hexDelegate selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[ascii enclosingScrollView] contentView]];
|
||||
}
|
||||
|
||||
// insert the resources' data into the text fields
|
||||
[self refreshData:[resource data]];
|
||||
[[self window] setResizeIncrements:NSMakeSize(kWindowStepWidthPerChar * kWindowStepCharsPerStep, 1)];
|
||||
[[self window] setResizeIncrements:NSMakeSize(kWindowStepWidthPerChar * kWindowStepCharsPerStep * [[self window] userSpaceScaleFactor], 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)
|
||||
// here because we don't want these notifications 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];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceWasSavedNotification object:resource];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceWasSavedNotification object:backup];
|
||||
if(liveEdit) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceDataDidChangeNotification object:resource];
|
||||
else [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceDataDidChangeNotification object:backup];
|
||||
|
||||
// put other notifications here too, just for togetherness
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[offset enclosingScrollView] contentView]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[hex enclosingScrollView] contentView]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[ascii enclosingScrollView] contentView]];
|
||||
|
||||
// finally, show the window
|
||||
// finally, set the window title & show the window
|
||||
[[self window] setTitle:[resource defaultWindowTitle]];
|
||||
[self showWindow:self];
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)notification
|
||||
{
|
||||
int width = [[notification object] frame].size.width;
|
||||
float width = [[(NSWindow *)[notification object] contentView] 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)];
|
||||
[[hex enclosingScrollView] setFrameSize:NSMakeSize((bytesPerRow * 21) + 5, [[hex enclosingScrollView] frame].size.height)];
|
||||
[[ascii enclosingScrollView] setFrameOrigin:NSMakePoint((bytesPerRow * 21) + 95, 20)];
|
||||
[[ascii enclosingScrollView] setFrameSize:NSMakeSize((bytesPerRow * 7) + 28, [[ascii enclosingScrollView] frame].size.height)];
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
// swap paste: menu item for my own paste submenu
|
||||
NSMenu *editMenu = [[[NSApp mainMenu] itemAtIndex:2] submenu];
|
||||
NSMenuItem *copyItem = [editMenu itemAtIndex:[editMenu indexOfItemWithTarget:nil andAction:@selector(copy:)]];
|
||||
NSMenuItem *pasteItem = [editMenu itemAtIndex:[editMenu indexOfItemWithTarget:nil andAction:@selector(paste:)]];
|
||||
[NSBundle loadNibNamed:@"PasteMenu" owner:self];
|
||||
|
||||
// swap copy: menu item for my own copy submenu
|
||||
[copyItem setEnabled:YES];
|
||||
[copyItem setKeyEquivalent:@"\0"]; // clear key equiv.
|
||||
[copyItem setKeyEquivalentModifierMask:0];
|
||||
[editMenu setSubmenu:copySubmenu forItem:copyItem];
|
||||
|
||||
// swap paste: menu item for my own paste submenu
|
||||
[pasteItem setEnabled:YES];
|
||||
[pasteItem setKeyEquivalent:@"\0"]; // clear key equiv. (yes, really!)
|
||||
[pasteItem setKeyEquivalent:@"\0"];
|
||||
[pasteItem setKeyEquivalentModifierMask:0];
|
||||
[editMenu setSubmenu:pasteSubmenu forItem:pasteItem];
|
||||
}
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification
|
||||
{
|
||||
// swap my submenu for plain paste menu item
|
||||
NSMenu *editMenu = [[[NSApp mainMenu] itemAtIndex:2] submenu];
|
||||
NSMenuItem *copyItem = [editMenu itemAtIndex:[editMenu indexOfItemWithSubmenu:copySubmenu]];
|
||||
NSMenuItem *pasteItem = [editMenu itemAtIndex:[editMenu indexOfItemWithSubmenu:pasteSubmenu]];
|
||||
|
||||
// swap my submenu for plain copy menu item
|
||||
[editMenu setSubmenu:nil forItem:copyItem];
|
||||
[copyItem setTarget:nil];
|
||||
[copyItem setAction:@selector(copy:)];
|
||||
[copyItem setKeyEquivalent:@"c"];
|
||||
[copyItem setKeyEquivalentModifierMask:NSCommandKeyMask];
|
||||
|
||||
// swap my submenu for plain paste menu item
|
||||
[editMenu setSubmenu:nil forItem:pasteItem];
|
||||
[pasteItem setTarget:nil];
|
||||
[pasteItem setAction:@selector(paste:)];
|
||||
@ -132,7 +149,7 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
{
|
||||
if([[self window] isDocumentEdited])
|
||||
{
|
||||
NSBeginAlertSheet( @"Do you want to save the changes you made to this resource?", @"Save", @"DonÕt Save", @"Cancel", sender, self, @selector(saveSheetDidClose:returnCode:contextInfo:), nil, nil, @"Your changes will be lost if you don't save them." );
|
||||
NSBeginAlertSheet(@"Do you want to keep the changes you made to this resource?", @"Keep", @"DonÕt Keep", @"Cancel", sender, self, @selector(saveSheetDidClose:returnCode:contextInfo:), nil, nil, @"Your changes cannot be saved later if you don't keep them.");
|
||||
return NO;
|
||||
}
|
||||
else return YES;
|
||||
@ -142,13 +159,12 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
{
|
||||
switch(returnCode)
|
||||
{
|
||||
case NSAlertDefaultReturn: // save
|
||||
[self saveResource];
|
||||
case NSAlertDefaultReturn: // keep
|
||||
[self saveResource:nil];
|
||||
[[self window] close];
|
||||
break;
|
||||
|
||||
case NSAlertAlternateReturn: // don't save
|
||||
[self revertResource];
|
||||
case NSAlertAlternateReturn: // don't keep
|
||||
[[self window] close];
|
||||
break;
|
||||
|
||||
@ -157,82 +173,32 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
}
|
||||
}
|
||||
|
||||
- (void)saveResource
|
||||
- (void)saveResource:(id)sender
|
||||
{
|
||||
if( liveEdit )
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillBeSavedNotification object:resource];
|
||||
[backup setData:[resource data]];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWasSavedNotification object:resource];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillBeSavedNotification object:backup];
|
||||
[backup setData:[resource data]];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWasSavedNotification object:backup];
|
||||
}
|
||||
[backup setData:[[resource data] copy]];
|
||||
}
|
||||
|
||||
- (void)revertResource
|
||||
- (void)revertResource:(id)sender
|
||||
{
|
||||
[resource setData:[backup data]];
|
||||
[resource setData:[[backup data] copy]];
|
||||
}
|
||||
|
||||
- (IBAction)showFind:(id)sender
|
||||
- (void)showFind:(id)sender
|
||||
{
|
||||
// bug: HexWindowController allocs a sheet controller, but it's never disposed of
|
||||
FindSheetController *sheetController = [[FindSheetController alloc] initWithWindowNibName:@"FindSheet"];
|
||||
[sheetController showFindSheet:self];
|
||||
}
|
||||
|
||||
- (void)viewDidScroll:(NSNotification *)notification
|
||||
{
|
||||
// get object refs for increased speed
|
||||
NSClipView *object = (NSClipView *) [notification object];
|
||||
NSClipView *offsetClip = [[offset enclosingScrollView] contentView];
|
||||
NSClipView *hexClip = [[hex enclosingScrollView] contentView];
|
||||
NSClipView *asciiClip = [[ascii enclosingScrollView] contentView];
|
||||
|
||||
// due to a bug in -[NSView setPostsBoundsChangedNotifications:] (it basically doesn't work), I am having to work around it by removing myself from the notification center and restoring things later on!
|
||||
// update, Apple say this isn't their bug. Yeah, right!
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewBoundsDidChangeNotification object:nil];
|
||||
|
||||
// when a view scrolls, update the other two
|
||||
if( object != offsetClip )
|
||||
{
|
||||
// [offsetClip setPostsBoundsChangedNotifications:NO];
|
||||
[offsetClip setBoundsOrigin:[object bounds].origin];
|
||||
// [offsetClip setPostsBoundsChangedNotifications:YES];
|
||||
}
|
||||
|
||||
if( object != hexClip )
|
||||
{
|
||||
// [hexClip setPostsBoundsChangedNotifications:NO];
|
||||
[hexClip setBoundsOrigin:[object bounds].origin];
|
||||
// [hexClip setPostsBoundsChangedNotifications:YES];
|
||||
}
|
||||
|
||||
if( object != asciiClip )
|
||||
{
|
||||
// [asciiClip setPostsBoundsChangedNotifications:NO];
|
||||
[asciiClip setBoundsOrigin:[object bounds].origin];
|
||||
// [asciiClip setPostsBoundsChangedNotifications:YES];
|
||||
}
|
||||
|
||||
// restore notifications
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:offsetClip];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:hexClip];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:asciiClip];
|
||||
}
|
||||
|
||||
- (void)resourceNameDidChange:(NSNotification *)notification
|
||||
{
|
||||
[[self window] setTitle:[(id <ResKnifeResourceProtocol>)[notification object] nameForEditorWindow]];
|
||||
[[self window] setTitle:[(id <ResKnifeResourceProtocol>)[notification object] defaultWindowTitle]];
|
||||
}
|
||||
|
||||
- (void)resourceDataDidChange:(NSNotification *)notification
|
||||
{
|
||||
// ensure it's our resource which got changed (should always be true, we don't register for other resource notifications)
|
||||
// bug: if liveEdit is false and another editor changes backup, if we are dirty we need to ask the user whether to accept the changes from the other editor and discard our changes, or vice versa.
|
||||
if([notification object] == (id)resource)
|
||||
{
|
||||
[self refreshData:[resource data]];
|
||||
@ -242,35 +208,21 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
|
||||
- (void)resourceWasSaved:(NSNotification *)notification
|
||||
{
|
||||
NSLog( @"%@; %@; %@", [notification object], resource, backup );
|
||||
if( [notification object] == (id)resource )
|
||||
id <ResKnifeResourceProtocol> object = [notification object];
|
||||
if(liveEdit)
|
||||
{
|
||||
// if resource gets saved, liveEdit is true and this resource is saving
|
||||
[backup setData:[resource data]];
|
||||
[self setDocumentEdited:NO];
|
||||
// haven't worked out what to do here yet
|
||||
}
|
||||
else if( [notification object] == (id)backup && !liveEdit )
|
||||
else
|
||||
{
|
||||
// backup will get saved by this resource if liveEdit is false, rather than the 'resource' variable
|
||||
// but really the data to preserve is in the resource variable
|
||||
[backup setData:[resource data]];
|
||||
// [self refreshData:[resource data]];
|
||||
[self setDocumentEdited:NO];
|
||||
}
|
||||
else if( [notification object] == (id)backup )
|
||||
{
|
||||
// backup will get saved by another editor too if liveEdit is false
|
||||
[resource setData:[backup data]];
|
||||
// [self refreshData:[resource data]];
|
||||
// this should refresh the view automatically
|
||||
[resource setData:[[object data] copy]];
|
||||
[self setDocumentEdited:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)refreshData:(NSData *)data;
|
||||
{
|
||||
NSDictionary *dictionary;
|
||||
NSMutableParagraphStyle *paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
|
||||
// save selections
|
||||
NSRange hexSelection = [hex selectedRange];
|
||||
NSRange asciiSelection = [ascii selectedRange];
|
||||
@ -281,13 +233,16 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
[ascii setDelegate:nil];
|
||||
|
||||
// prepare attributes dictionary
|
||||
NSMutableParagraphStyle *paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
[paragraph setLineBreakMode:NSLineBreakByCharWrapping];
|
||||
dictionary = [NSDictionary dictionaryWithObject:paragraph forKey:NSParagraphStyleAttributeName];
|
||||
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:paragraph forKey:NSParagraphStyleAttributeName];
|
||||
|
||||
// do stuff with data
|
||||
[offset setString:[hexDelegate offsetRepresentation:data]];
|
||||
[hex setString:[hexDelegate hexRepresentation:data]];
|
||||
[ascii setString:[hexDelegate asciiRepresentation:data]];
|
||||
if([data length] > 0)
|
||||
[hex setString:[[data hexRepresentation] stringByAppendingString:@" "]];
|
||||
else [hex setString:[data hexRepresentation]];
|
||||
[ascii setString:[data asciiRepresentation]];
|
||||
|
||||
// apply attributes
|
||||
[[offset textStorage] addAttributes:dictionary range:NSMakeRange(0, [[offset textStorage] length])];
|
||||
@ -318,6 +273,11 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
return bytesPerRow;
|
||||
}
|
||||
|
||||
- (NSMenu *)copySubmenu
|
||||
{
|
||||
return copySubmenu;
|
||||
}
|
||||
|
||||
- (NSMenu *)pasteSubmenu
|
||||
{
|
||||
return pasteSubmenu;
|
||||
@ -328,4 +288,36 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
return undoManager;
|
||||
}
|
||||
|
||||
/* range conversion methods */
|
||||
|
||||
+ (NSRange)byteRangeFromHexRange:(NSRange)hexRange
|
||||
{
|
||||
// valid for all window widths
|
||||
NSRange byteRange = NSMakeRange(0,0);
|
||||
byteRange.location = (hexRange.location / 3);
|
||||
byteRange.length = (hexRange.length / 3) + ((hexRange.length % 3)? 1:0);
|
||||
return byteRange;
|
||||
}
|
||||
|
||||
+ (NSRange)hexRangeFromByteRange:(NSRange)byteRange
|
||||
{
|
||||
// valid for all window widths
|
||||
NSRange hexRange = NSMakeRange(0,0);
|
||||
hexRange.location = (byteRange.location * 3);
|
||||
hexRange.length = (byteRange.length * 3) - ((byteRange.length > 0)? 1:0);
|
||||
return hexRange;
|
||||
}
|
||||
|
||||
+ (NSRange)byteRangeFromAsciiRange:(NSRange)asciiRange
|
||||
{
|
||||
// one-to-one mapping
|
||||
return asciiRange;
|
||||
}
|
||||
|
||||
+ (NSRange)asciiRangeFromByteRange:(NSRange)byteRange
|
||||
{
|
||||
// one-to-one mapping
|
||||
return byteRange;
|
||||
}
|
||||
|
||||
@end
|
@ -1,34 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!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>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Hexadecimal Editor</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.nickshanks.resknife.hexadecimal</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string></string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string></string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>ResK</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.0.1d1</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>HexWindow</string>
|
||||
<string>3</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>HexWindowController</string>
|
||||
<key>RKEditedType</key>
|
||||
<key>RKSupportedTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>IsResKnifeDefaultForType</key>
|
||||
<string>YES</string>
|
||||
<key>RKTypeName</key>
|
||||
<string>Hexadecimal Editor</string>
|
||||
<key>RKTypeRole</key>
|
||||
<string>Editor</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
BIN
Cocoa/Resources/Apply3.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
Cocoa/Resources/Button_certified.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Cocoa/Resources/Button_reload.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Cocoa/Resources/Create48.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
Cocoa/Resources/Delete.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
93
Cocoa/Resources/Delete.svg
Normal file
@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" ?>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="960px"
|
||||
height="960px">
|
||||
<defs>
|
||||
<linearGradient id="linearGradient1">
|
||||
<stop style="stop-color:#ef2929" offset="0" />
|
||||
<stop style="stop-color:#cc0000" offset="1" />
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="linearGradient2">
|
||||
<stop offset="0" style="stop-color:black;stop-opacity:1;" />
|
||||
<stop offset="1" style="stop-color:black;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
|
||||
<radialGradient id="radialGradient1"
|
||||
xlink:href="#linearGradient2"
|
||||
gradientTransform="matrix(1,0,0,0.500000,1.635742e-14,20)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
r="17.142857"
|
||||
fy="40"
|
||||
fx="23.857143"
|
||||
cy="40"
|
||||
cx="23.857143" />
|
||||
|
||||
<radialGradient id="radialGradient2"
|
||||
xlink:href="#linearGradient1"
|
||||
gradientTransform="matrix(-1.262871,2.796553e-2,-3.606716e-2,-1.629656,47.36662,36.49787)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="20.935379"
|
||||
cy="12.592707"
|
||||
fx="20.935379"
|
||||
fy="12.592707"
|
||||
r="19.967958" />
|
||||
</defs>
|
||||
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Delete</dc:title>
|
||||
<dc:date>2007-02-20</dc:date>
|
||||
<dc:creator>
|
||||
<rdf:Bag>
|
||||
<rdf:li><cc:Agent><dc:title>Andreas Nilsson</dc:title></cc:Agent></rdf:li>
|
||||
<rdf:li><cc:Agent><dc:title>Nicholas Shanks</dc:title></cc:Agent></rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:creator>
|
||||
<dc:source>http://tango-project.org/</dc:source>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>delete</rdf:li>
|
||||
<rdf:li>remove</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
|
||||
</cc:Work>
|
||||
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
|
||||
<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:requires rdf:resource="http://web.resource.org/cc/Attribution" />
|
||||
<cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="scale(20,20)">
|
||||
<path style="opacity:0.52688169;color:black;fill:url(#radialGradient1);stroke:none;"
|
||||
transform="matrix(1.225,0,0,0.408334,-5.221224,25.17622)"
|
||||
d="M 41 40 A 17.142857 8.5714283 0 1 1 6.7142868,40 A 17.142857 8.5714283 0 1 1 41 40 z" />
|
||||
|
||||
<path style="fill:url(#radialGradient2);stroke:#a40000;"
|
||||
d="M 24.035816,3.5720836 C 13.289574,3.5720836 4.5678570,12.294146 4.5678580,23.040834 C 4.5678580,33.787521 13.289575,42.509583 24.035816,42.509584 C 34.782058,42.509584 43.503776,33.787520 43.503775,23.040834 C 43.503775,12.294147 34.782058,3.5720836 24.035816,3.5720836 z M 24.004517,8.4783336 C 32.049892,8.4783336 38.589837,14.990984 38.589837,23.009584 C 38.589837,25.981868 37.657973,28.737374 36.117218,31.040834 L 15.960683,10.915834 C 18.272680,9.3813936 21.022553,8.4783336 24.004517,8.4783336 z M 12.267404,14.447084 L 32.580435,34.728334 C 30.166684,36.490827 27.221538,37.540834 24.004517,37.540834 C 15.959141,37.540834 9.4191980,31.028184 9.4191980,23.009584 C 9.4191980,19.803270 10.497961,16.851741 12.267404,14.447084 z " />
|
||||
|
||||
<path style="opacity:0.55376345;fill:none;stroke:white;"
|
||||
transform="matrix(1.007576,0,0,1.019157,-4.568194,-4.726048)"
|
||||
d="M 46.714287 27.214285 A 18.357143 18.142857 0 1 1 10,27.214285 A 18.357143 18.142857 0 1 1 46.714287 27.214285 z" />
|
||||
|
||||
<path style="opacity:0.47849461;fill:none;stroke:white;"
|
||||
d="M 15.075203,11.366727 L 35.646632,31.938156" />
|
||||
|
||||
<!--path style="opacity:0.30645159;fill:white;stroke:none;"
|
||||
d="M 4.4323460,19.795298 C 4.4561550,21.985774 9.8371077,20.461965 9.8609167,21.652441 C 9.8132977,19.842917 11.837108,15.961965 12.289489,15.152441 L 20.932346,23.509584 C 20.884728,21.771489 27.122823,23.390537 27.003776,21.509584 L 16.718061,10.866727 C 18.241871,10.081013 21.837109,8.7952976 24.075204,8.9381546 C 32.313299,9.1524406 38.051394,16.795298 38.075204,22.009584 L 37.503775,27.009584 C 37.384727,28.866727 43.337108,26.795298 43.146632,28.295298 C 43.551394,27.152441 44.027584,24.795298 43.932346,22.081013 C 43.884727,12.438155 35.765679,3.3667266 24.003775,3.1524406 C 15.420441,3.2833936 8.4978220,8.1822026 6.1287740,14.661370 C 5.9933010,14.694830 4.6585360,16.842917 4.4323460,19.795298 z " /-->
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.9 KiB |
BIN
Cocoa/Resources/Delete3.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
Cocoa/Resources/Go3.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
Cocoa/Resources/Help.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Cocoa/Resources/Help3.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
Cocoa/Resources/ResKnife-old.icns
Normal file
43
Cocoa/Resources/Resource Type Mappings.strings
Normal file
@ -0,0 +1,43 @@
|
||||
/* Resource type to file type mapping table */
|
||||
|
||||
/* useful for mangling a resource type to yield an icon for a different file extension */
|
||||
/* also could be used in future for binding a resource to an external editor (the default editor for the corrisponding file type) */
|
||||
/* acceptable values are:
|
||||
- file name extensions
|
||||
- MacOS file types (four characters in single quotes)
|
||||
- bundle identifiers
|
||||
*/
|
||||
|
||||
"cfrg" = "shlb";
|
||||
"SIZE" = "shlb";
|
||||
|
||||
"CODE" = "s";
|
||||
"MWBB" = "'MMPF'";
|
||||
"MWKB" = "'MMPF'";
|
||||
|
||||
"STR " = "text";
|
||||
"STR#" = "text";
|
||||
|
||||
"plst" = "plist";
|
||||
"snd " = "'sfil'";
|
||||
"url " = "webloc";
|
||||
|
||||
"hfdr" = "com.apple.finder";
|
||||
|
||||
"cicn" = "icns";
|
||||
"SICN" = "icns";
|
||||
"icl8" = "icns";
|
||||
"icl4" = "icns";
|
||||
"ICON" = "icns";
|
||||
"ICN#" = "icns";
|
||||
"ics8" = "icns";
|
||||
"ics4" = "icns";
|
||||
"ics#" = "icns";
|
||||
"icm8" = "icns";
|
||||
"icm4" = "icns";
|
||||
"icm#" = "icns";
|
||||
|
||||
"PNG " = "png";
|
||||
|
||||
"NFNT" = "'tfil'";
|
||||
"sfnt" = "ttf";
|
BIN
Cocoa/Resources/Resource file-old.icns
Normal file
BIN
Cocoa/Resources/Search3.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
Cocoa/Resources/add.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
@ -1,6 +1,6 @@
|
||||
{
|
||||
PreserveBackups = YES;
|
||||
Autosave = YES;
|
||||
Autosave = NO;
|
||||
AutosaveInterval = 5;
|
||||
DeleteResourceWarning = YES;
|
||||
|
||||
|
BIN
Cocoa/Resources/delete-1.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
88
Cocoa/cy.lproj/Application.nib/classes.nib
generated
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
IBClasses = (
|
||||
{
|
||||
ACTIONS = {
|
||||
emailDeveloper = id;
|
||||
showAbout = id;
|
||||
showInfo = id;
|
||||
showPasteboard = id;
|
||||
showPrefs = id;
|
||||
visitSourceforge = id;
|
||||
visitWebsite = id;
|
||||
};
|
||||
CLASS = ApplicationDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {openPanelDelegate = OpenPanelDelegate; };
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{
|
||||
ACTIONS = {
|
||||
deselectAll = id;
|
||||
exportResourceToFile = id;
|
||||
exportResourceToImageFile = id;
|
||||
findNext = id;
|
||||
findPrevious = id;
|
||||
findWithSelection = id;
|
||||
openResources = id;
|
||||
openResourcesAsHex = id;
|
||||
openResourcesInTemplate = id;
|
||||
playSound = id;
|
||||
revertResource = id;
|
||||
saveResource = id;
|
||||
scrollToSelection = id;
|
||||
showAbout = id;
|
||||
showCreateResourceSheet = id;
|
||||
showExportToDFSheet = id;
|
||||
showFind = id;
|
||||
showInfo = id;
|
||||
showPrefs = id;
|
||||
showSelectTemplateSheet = id;
|
||||
useIconView = id;
|
||||
useListView = id;
|
||||
};
|
||||
CLASS = FirstResponder;
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{CLASS = NSOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; },
|
||||
{
|
||||
ACTIONS = {addFork = id; removeFork = id; };
|
||||
CLASS = OpenPanelDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
addForkButton = NSButton;
|
||||
forkTableView = NSTableView;
|
||||
openPanelAccessoryView = NSView;
|
||||
removeForkButton = NSButton;
|
||||
};
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{CLASS = OutlineSortView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; },
|
||||
{
|
||||
ACTIONS = {
|
||||
clear = id;
|
||||
copy = id;
|
||||
creatorChanged = id;
|
||||
exportResourceToFile = id;
|
||||
exportResourceToImageFile = id;
|
||||
openResources = id;
|
||||
openResourcesAsHex = id;
|
||||
openResourcesInTemplate = id;
|
||||
paste = id;
|
||||
playSound = id;
|
||||
showCreateResourceSheet = id;
|
||||
showSelectTemplateSheet = id;
|
||||
typeChanged = id;
|
||||
};
|
||||
CLASS = ResourceDocument;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
dataSource = ResourceDataSource;
|
||||
mainWindow = NSWindow;
|
||||
outlineView = NSOutlineView;
|
||||
};
|
||||
SUPERCLASS = NSDocument;
|
||||
}
|
||||
);
|
||||
IBVersion = 1;
|
||||
}
|
27
Cocoa/cy.lproj/Application.nib/info.nib
generated
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!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>75 727 356 240 0 0 1600 1002 </string>
|
||||
<key>IBEditorPositions</key>
|
||||
<dict>
|
||||
<key>246</key>
|
||||
<string>569 580 520 175 0 0 1600 1002 </string>
|
||||
<key>29</key>
|
||||
<string>66 658 413 44 0 0 1600 1002 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>446.1</string>
|
||||
<key>IBLockedObjects</key>
|
||||
<array/>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>1</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>29</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>8P135</string>
|
||||
</dict>
|
||||
</plist>
|
BIN
Cocoa/cy.lproj/Application.nib/keyedobjects.nib
generated
Normal file
BIN
Cocoa/cy.lproj/Application.nib/objects.nib
generated
Normal file
6
Cocoa/cy.lproj/InfoPlist.strings
Normal file
@ -0,0 +1,6 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
CFBundleName = "ResKnife";
|
||||
CFBundleShortVersionString = "0.6 beta 4";
|
||||
CFBundleGetInfoString = "ResKnife 0.6 b4, Hawlfraint © Nicolas Siancs, 2001-7.";
|
||||
NSHumanReadableCopyright = "© Nicolas Siancs, 2001-7.";
|
BIN
Cocoa/cy.lproj/Localizable.strings
Normal file
88
Cocoa/gd.lproj/Application.nib/classes.nib
generated
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
IBClasses = (
|
||||
{
|
||||
ACTIONS = {
|
||||
emailDeveloper = id;
|
||||
showAbout = id;
|
||||
showInfo = id;
|
||||
showPasteboard = id;
|
||||
showPrefs = id;
|
||||
visitSourceforge = id;
|
||||
visitWebsite = id;
|
||||
};
|
||||
CLASS = ApplicationDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {openPanelDelegate = OpenPanelDelegate; };
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{
|
||||
ACTIONS = {
|
||||
deselectAll = id;
|
||||
exportResourceToFile = id;
|
||||
exportResourceToImageFile = id;
|
||||
findNext = id;
|
||||
findPrevious = id;
|
||||
findWithSelection = id;
|
||||
openResources = id;
|
||||
openResourcesAsHex = id;
|
||||
openResourcesInTemplate = id;
|
||||
playSound = id;
|
||||
revertResource = id;
|
||||
saveResource = id;
|
||||
scrollToSelection = id;
|
||||
showAbout = id;
|
||||
showCreateResourceSheet = id;
|
||||
showExportToDFSheet = id;
|
||||
showFind = id;
|
||||
showInfo = id;
|
||||
showPrefs = id;
|
||||
showSelectTemplateSheet = id;
|
||||
useIconView = id;
|
||||
useListView = id;
|
||||
};
|
||||
CLASS = FirstResponder;
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{CLASS = NSOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; },
|
||||
{
|
||||
ACTIONS = {addFork = id; removeFork = id; };
|
||||
CLASS = OpenPanelDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
addForkButton = NSButton;
|
||||
forkTableView = NSTableView;
|
||||
openPanelAccessoryView = NSView;
|
||||
removeForkButton = NSButton;
|
||||
};
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{CLASS = OutlineSortView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; },
|
||||
{
|
||||
ACTIONS = {
|
||||
clear = id;
|
||||
copy = id;
|
||||
creatorChanged = id;
|
||||
exportResourceToFile = id;
|
||||
exportResourceToImageFile = id;
|
||||
openResources = id;
|
||||
openResourcesAsHex = id;
|
||||
openResourcesInTemplate = id;
|
||||
paste = id;
|
||||
playSound = id;
|
||||
showCreateResourceSheet = id;
|
||||
showSelectTemplateSheet = id;
|
||||
typeChanged = id;
|
||||
};
|
||||
CLASS = ResourceDocument;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
dataSource = ResourceDataSource;
|
||||
mainWindow = NSWindow;
|
||||
outlineView = NSOutlineView;
|
||||
};
|
||||
SUPERCLASS = NSDocument;
|
||||
}
|
||||
);
|
||||
IBVersion = 1;
|
||||
}
|
27
Cocoa/gd.lproj/Application.nib/info.nib
generated
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!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>75 727 356 240 0 0 1600 1002 </string>
|
||||
<key>IBEditorPositions</key>
|
||||
<dict>
|
||||
<key>246</key>
|
||||
<string>567 580 520 175 0 0 1600 1002 </string>
|
||||
<key>29</key>
|
||||
<string>408 624 463 44 0 0 1600 1002 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>446.1</string>
|
||||
<key>IBLockedObjects</key>
|
||||
<array/>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>1</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>29</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>8L127</string>
|
||||
</dict>
|
||||
</plist>
|
BIN
Cocoa/gd.lproj/Application.nib/keyedobjects.nib
generated
Normal file
BIN
Cocoa/gd.lproj/Application.nib/objects.nib
generated
Normal file
6
Cocoa/gd.lproj/InfoPlist.strings
Normal file
@ -0,0 +1,6 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
CFBundleName = "ResKnife";
|
||||
CFBundleShortVersionString = "0.6 beta 4";
|
||||
CFBundleGetInfoString = "ResKnife 0.6 b4, Dlighe-sgrìobhaidh © Nicolas Sauncs, 2001-7.";
|
||||
NSHumanReadableCopyright = "© Nicolas Sauncs, 2001-7.";
|
BIN
Cocoa/gd.lproj/Localizable.strings
Normal file
50
Cocoa/ja.lproj/Application.nib/classes.nib
generated
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
IBClasses = (
|
||||
{
|
||||
ACTIONS = {
|
||||
emailDeveloper = id;
|
||||
showAbout = id;
|
||||
showInfo = id;
|
||||
showPasteboard = id;
|
||||
showPrefs = id;
|
||||
visitSourceforge = id;
|
||||
visitWebsite = id;
|
||||
};
|
||||
CLASS = ApplicationDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {openPanelDelegate = OpenPanelDelegate; };
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{
|
||||
ACTIONS = {
|
||||
deselectAll = id;
|
||||
openResources = id;
|
||||
openResourcesAsHex = id;
|
||||
openResourcesInTemplate = id;
|
||||
playSound = id;
|
||||
revertResource = id;
|
||||
saveResource = id;
|
||||
showCreateResourceSheet = id;
|
||||
showSelectTemplateSheet = id;
|
||||
useIconView = id;
|
||||
useListView = id;
|
||||
};
|
||||
CLASS = FirstResponder;
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{
|
||||
ACTIONS = {addFork = id; removeFork = id; };
|
||||
CLASS = OpenPanelDelegate;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
addForkButton = NSButton;
|
||||
forkTableView = NSTableView;
|
||||
openPanelAccessoryView = NSView;
|
||||
removeForkButton = NSButton;
|
||||
};
|
||||
SUPERCLASS = NSObject;
|
||||
}
|
||||
);
|
||||
IBVersion = 1;
|
||||
}
|
23
Cocoa/ja.lproj/Application.nib/info.nib
generated
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!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>454 731 356 240 0 0 1600 1002 </string>
|
||||
<key>IBEditorPositions</key>
|
||||
<dict>
|
||||
<key>252</key>
|
||||
<string>580 400 520 175 0 0 1600 1002 </string>
|
||||
<key>29</key>
|
||||
<string>465 651 429 44 0 0 1600 1002 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>446.1</string>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>29</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>8L127</string>
|
||||
</dict>
|
||||
</plist>
|
BIN
Cocoa/ja.lproj/Application.nib/keyedobjects.nib
generated
Normal file
@ -1,5 +1,9 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/*!
|
||||
@function main
|
||||
*/
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, argv);
|
||||
|
@ -82,7 +82,7 @@
|
||||
resImage = [[NSImage alloc] init];
|
||||
|
||||
resData = [[resource data] retain];
|
||||
planes[0] = (char*) [resData bytes];
|
||||
planes[0] = (unsigned char*) [resData bytes];
|
||||
|
||||
if( [resType isEqualToString: @"ICN#"] )
|
||||
{
|
||||
|
@ -1,39 +1,36 @@
|
||||
ABOUT THE CODE
|
||||
--------------
|
||||
|
||||
|
||||
WHAT HAPPENS WHEN A TEMPLATE EDITOR IS OPENED FOR A RESOURCE
|
||||
|
||||
The template editor uses a dedicated class for each field type (or family of field types).
|
||||
These classes are all subclasses of the common base class NuTemplateElement. For things like
|
||||
lists, there is a subclass NuTemplateGroupElement from which you can instead subclass to
|
||||
These classes are all subclasses of the common base class Element. For things like
|
||||
lists, there is a subclass GroupElement from which you can instead subclass to
|
||||
have some of the work done for you.
|
||||
|
||||
When opening a resource, the template editor first creates a NuTemplateStream for the template
|
||||
When opening a resource, the template editor first creates a TemplateStream for the template
|
||||
resource and calls readOneObject:on it until it runs out of data, instantiating a hierarchy
|
||||
of NuTemplateElement subclasses for based on the template.
|
||||
of Element subclasses for based on the template.
|
||||
|
||||
After that, it creates a NuTemplateStream for the resource and loops over the template object
|
||||
After that, it creates a TemplateStream for the resource and loops over the template object
|
||||
hierarchy, creating a copy of each item, and then calling readDataFrom:containingArray:on
|
||||
the copy, which in turn reads data from the NuTemplateStream and stores it in its instance
|
||||
variables. For this to work, subclasses of NuTemplateElement *must* implement the NSCopying
|
||||
the copy, which in turn reads data from the TemplateStream and stores it in its instance
|
||||
variables. For this to work, subclasses of Element *must* implement the NSCopying
|
||||
protocol.
|
||||
|
||||
This results in an object hierarchy that describes the entire resource using template fields
|
||||
containing the data, which can now be edited, displayed in lists, etc.
|
||||
|
||||
|
||||
WHAT HAPPENS WHEN THE TEMPLATE EDITOR IS CLOSED
|
||||
|
||||
As soon as the template editor is closed, another NuTemplateStream is created for the
|
||||
As soon as the template editor is closed, another TemplateStream is created for the
|
||||
resource and passed to all template fields (the copies with the resource data, not the
|
||||
pre-parsed template hierarchy), via writeDataTo:, which is where they should write their
|
||||
data to the stream. Before that, sizeOnDisk is called on each NuTemplateElement to
|
||||
data to the stream. Before that, sizeOnDisk is called on each Element to
|
||||
calculate the new size of the resource before the actual process of writing them out.
|
||||
This size must include the size of all of their sub-items, and writeDataTo:must call
|
||||
these sub items if they are to be written to disk.
|
||||
|
||||
|
||||
SPECIAL CASE:LISTS
|
||||
|
||||
When the editor encounters an LSTB element, the LSTB element is called upon to parse its
|
||||
@ -65,8 +62,7 @@ Analogous behaviour is employed for other kinds of lists, except that additional
|
||||
features in LSTEs are activated to allow writing terminating zeroes to the file, and
|
||||
that the equivalent to the "LSTB" item may also update a counter field.
|
||||
|
||||
|
||||
|
||||
REVISIONS:
|
||||
2006-02-05 NS Rewrote plugin.
|
||||
2003-08-13 UK Finished chapter on lists, added revision history.
|
||||
2003-08-08 UK Created.
|