Changes accumulated on my G5 while repository was inaccessible.
@ -10,7 +10,7 @@
|
|||||||
else return [self itemAtRow:[self selectedRow]];
|
else return [self itemAtRow:[self selectedRow]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)selectedItems;
|
- (NSArray *)selectedItems
|
||||||
{
|
{
|
||||||
NSNumber *row;
|
NSNumber *row;
|
||||||
NSMutableArray *items = [NSMutableArray array];
|
NSMutableArray *items = [NSMutableArray array];
|
||||||
|
@ -6,3 +6,11 @@
|
|||||||
- (FSSpec *)createFSSpec;
|
- (FSSpec *)createFSSpec;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@interface NSString (ResKnifeBooleanExtensions)
|
||||||
|
|
||||||
|
- (BOOL)boolValue;
|
||||||
|
+ (NSString *)stringWithBool:(BOOL)boolean;
|
||||||
|
|
||||||
|
@end
|
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
- (FSRef *)createFSRef
|
- (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);
|
OSStatus error = FSPathMakeRef([self fileSystemRepresentation], fsRef, NULL);
|
||||||
if(error == noErr)
|
if(error == noErr)
|
||||||
return fsRef;
|
return fsRef;
|
||||||
@ -13,16 +14,36 @@
|
|||||||
|
|
||||||
- (FSSpec *)createFSSpec
|
- (FSSpec *)createFSSpec
|
||||||
{
|
{
|
||||||
FSRef *fsRef = NULL;
|
// caller is responsible for disposing of the FSSpec (method is a 'create' method)
|
||||||
FSSpec *fsSpec = NULL;
|
FSRef *fsRef = (FSRef *) NewPtrClear(sizeof(FSRef));
|
||||||
|
FSSpec *fsSpec = (FSSpec *) NewPtrClear(sizeof(FSSpec));
|
||||||
OSStatus error = FSPathMakeRef([self fileSystemRepresentation], fsRef, NULL);
|
OSStatus error = FSPathMakeRef([self fileSystemRepresentation], fsRef, NULL);
|
||||||
if(error == noErr)
|
if(error == noErr)
|
||||||
{
|
{
|
||||||
error = FSGetCatalogInfo(fsRef, kFSCatInfoNone, NULL, NULL, fsSpec, NULL);
|
error = FSGetCatalogInfo(fsRef, kFSCatInfoNone, NULL, NULL, fsSpec, NULL);
|
||||||
if(error == noErr)
|
if(error == noErr)
|
||||||
|
{
|
||||||
|
DisposePtr((Ptr) fsRef);
|
||||||
return fsSpec;
|
return fsSpec;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
DisposePtr((Ptr) fsRef);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@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>
|
#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
|
@interface ApplicationDelegate : NSObject
|
||||||
{
|
{
|
||||||
/*! @var openAuxView Accessory view for <tt>NSOpenPanels</tt>. */
|
/*! @var openPanelDelegate Delegate for <tt>NSOpenPanels</tt>. */
|
||||||
IBOutlet NSView *openAuxView;
|
IBOutlet OpenPanelDelegate *openPanelDelegate;
|
||||||
/*! @var forkTableView Table view inside <tt>openAuxView</tt>. */
|
|
||||||
IBOutlet NSTableView *forkTableView;
|
|
||||||
/*! @var icons A dictionary within which to cache icons. Keys are four-character <tt>NSStrings</tt> representing <tt>ResTypes</tt>. */
|
/*! @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;
|
- (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;
|
- (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;
|
- (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;
|
- (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;
|
- (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;
|
- (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;
|
- (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;
|
- (void)initUserDefaults;
|
||||||
|
|
||||||
/*! @function openAuxView
|
/* accessors */
|
||||||
* @discussion Accessor method for the <tt>openAuxView</tt> instance variable.
|
|
||||||
*/
|
|
||||||
- (NSView *)openAuxView;
|
|
||||||
|
|
||||||
/*! @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;
|
- (NSDictionary *)icons;
|
||||||
|
|
||||||
@end
|
/* utility methods */
|
||||||
|
|
||||||
@interface NSSavePanel (PackageBrowser)
|
- (NSArray *)forksForFile:(FSRef *)fileRef;
|
||||||
|
|
||||||
@end
|
@end
|
@ -1,4 +1,5 @@
|
|||||||
#import "ApplicationDelegate.h"
|
#import "ApplicationDelegate.h"
|
||||||
|
#import "OpenPanelDelegate.h"
|
||||||
#import "RKDocumentController.h"
|
#import "RKDocumentController.h"
|
||||||
#import "InfoWindowController.h"
|
#import "InfoWindowController.h"
|
||||||
#import "PasteboardWindowController.h"
|
#import "PasteboardWindowController.h"
|
||||||
@ -6,8 +7,9 @@
|
|||||||
#import "CreateResourceSheetController.h"
|
#import "CreateResourceSheetController.h"
|
||||||
#import "ResourceDocument.h"
|
#import "ResourceDocument.h"
|
||||||
#import "ResourceDataSource.h"
|
#import "ResourceDataSource.h"
|
||||||
|
#import "RKEditorRegistry.h"
|
||||||
|
|
||||||
#import "ResknifePluginProtocol.h"
|
#import "ResKnifePluginProtocol.h"
|
||||||
#import "RKSupportResourceRegistry.h"
|
#import "RKSupportResourceRegistry.h"
|
||||||
|
|
||||||
|
|
||||||
@ -23,42 +25,96 @@
|
|||||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
// instanciate my own subclass of NSDocumentController so I can override the open dialog
|
// instanciate my own subclass of NSDocumentController so I can override the open dialog
|
||||||
RKDocumentController *docController = [[RKDocumentController alloc] init];
|
[[RKDocumentController alloc] init];
|
||||||
|
[RKSupportResourceRegistry scanForSupportResources];
|
||||||
[RKSupportResourceRegistry scanForSupportResources: [NSDocumentController sharedDocumentController]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method awakeFromNib
|
||||||
|
@updated 2003-10-24 NGS: moved icon caching into method called by timer (to speed up app launch time)
|
||||||
|
*/
|
||||||
|
|
||||||
- (void)awakeFromNib
|
- (void)awakeFromNib
|
||||||
{
|
{
|
||||||
NSTableColumn *tableColumn;
|
|
||||||
NSButtonCell *buttonCell;
|
|
||||||
|
|
||||||
// Part of my EvilPlanª to find out how many people use ResKnife and how often!
|
// Part of my EvilPlanª to find out how many people use ResKnife and how often!
|
||||||
int launchCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"];
|
int launchCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"];
|
||||||
[[NSUserDefaults standardUserDefaults] setInteger:launchCount + 1 forKey:@"LaunchCount"];
|
[[NSUserDefaults standardUserDefaults] setInteger:launchCount + 1 forKey:@"LaunchCount"];
|
||||||
|
|
||||||
// save a number of icons
|
// initalise an empty icon cache and create timer used to pre-cache a number of common icons
|
||||||
icons = [[NSMutableDictionary alloc] init];
|
_icons = [[NSMutableDictionary alloc] init];
|
||||||
[icons setObject:[[NSWorkspace sharedWorkspace] iconForFileType:@"TEXT"] forKey:@"TEXT"];
|
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(precacheIcons:) userInfo:nil repeats:NO];
|
||||||
[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];
|
|
||||||
|
|
||||||
|
// set default preferences
|
||||||
[self initUserDefaults];
|
[self initUserDefaults];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
[icons release];
|
[_icons release];
|
||||||
[super dealloc];
|
[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
|
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
|
||||||
{
|
{
|
||||||
#pragma unused(sender)
|
#pragma unused(sender)
|
||||||
@ -89,8 +145,14 @@
|
|||||||
|
|
||||||
- (IBAction)showAbout:(id)sender
|
- (IBAction)showAbout:(id)sender
|
||||||
{
|
{
|
||||||
[NSApp orderFrontStandardAboutPanel:sender];
|
// could do with a better about box
|
||||||
// get about box code from http://cocoadevcentral.com/tutorials/showpage.php?show=00000041.php
|
/* 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
|
- (IBAction)visitWebsite:(id)sender
|
||||||
@ -160,26 +222,94 @@
|
|||||||
[defaults synchronize];
|
[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
|
- (NSDictionary *)icons
|
||||||
{
|
{
|
||||||
return icons;
|
return [NSDictionary dictionaryWithDictionary:[self _icons]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@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
|
@implementation CreateResourceSheetController
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/*!
|
||||||
controlTextDidChange:
|
@method controlTextDidChange:
|
||||||
Someone changed the control ID edit field. Check whether this is
|
@abstract Handles updating of the 'Create' button when valid values are present in the sheet's fields.
|
||||||
a unique ID and appropriately enable the "create" button.
|
@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>
|
||||||
Check "notification" against being nil, which is how we call it when
|
@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.
|
||||||
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.
|
|
||||||
-------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
- (void)controlTextDidChange:(NSNotification *)notification
|
- (void)controlTextDidChange:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
@ -37,16 +29,12 @@
|
|||||||
[createButton setEnabled:enableButton];
|
[createButton setEnabled:enableButton];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
/* -----------------------------------------------------------------------------
|
@method showCreateResourceSheet:
|
||||||
showCreateResourceSheet:
|
@abstract Shows the sheet allowing the user to define the properties of a new resource.
|
||||||
Show our sheet and set it up before that.
|
@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.
|
||||||
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.
|
|
||||||
-------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
- (void)showCreateResourceSheet:(ResourceDocument *)sheetDoc
|
- (void)showCreateResourceSheet:(ResourceDocument *)sheetDoc
|
||||||
{
|
{
|
||||||
@ -54,13 +42,18 @@
|
|||||||
document = sheetDoc;
|
document = sheetDoc;
|
||||||
[NSApp beginSheet:[self window] modalForWindow:[document mainWindow] modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
[NSApp beginSheet:[self window] modalForWindow:[document mainWindow] modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
||||||
[resIDView setObjectValue:[[document dataSource] uniqueIDForType:[typeView stringValue]]];
|
[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
|
- (IBAction)hideCreateResourceSheet:(id)sender
|
||||||
{
|
{
|
||||||
if(sender == createButton)
|
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;
|
unsigned short attributes = 0;
|
||||||
attributes ^= [[attributesMatrix cellAtRow:0 column:0] intValue]? resPreload:0;
|
attributes ^= [[attributesMatrix cellAtRow:0 column:0] intValue]? resPreload:0;
|
||||||
attributes ^= [[attributesMatrix cellAtRow:1 column:0] intValue]? resPurgeable: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:0 column:1] intValue]? resSysHeap:0;
|
||||||
attributes ^= [[attributesMatrix cellAtRow:1 column:1] intValue]? resProtected: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 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)
|
if([[nameView stringValue] length] == 0)
|
||||||
[[document undoManager] setActionName:NSLocalizedString(@"Create Resource", nil)];
|
[[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];
|
[[document undoManager] endUndoGrouping];
|
||||||
}
|
}
|
||||||
[[self window] orderOut:nil];
|
[[self window] orderOut:nil];
|
||||||
[NSApp endSheet:[self window]];
|
[NSApp endSheet:[self window]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
/* -----------------------------------------------------------------------------
|
@method typePopupSelection:
|
||||||
typePopupSelection:
|
@abstract Updates the edit text field when the type pop-up selection is changed.
|
||||||
Someone chose an item from our "res type" popup menu. Update our
|
@updated 2003-08-01 UK: Commented, made it update state of "create" button.
|
||||||
edit field to show that.
|
*/
|
||||||
|
|
||||||
REVISIONS:
|
|
||||||
2003-08-01 UK Commented, made it update state of "create" button..
|
|
||||||
-------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
- (IBAction)typePopupSelection:(id)sender
|
- (IBAction)typePopupSelection:(id)sender
|
||||||
{
|
{
|
||||||
|
@ -35,7 +35,7 @@ enum Attributes
|
|||||||
- (void)updateInfoWindow;
|
- (void)updateInfoWindow;
|
||||||
- (void)setMainWindow:(NSWindow *)mainWindow;
|
- (void)setMainWindow:(NSWindow *)mainWindow;
|
||||||
- (IBAction)attributesChanged:(id)sender;
|
- (IBAction)attributesChanged:(id)sender;
|
||||||
- (IBAction)nameChanged: (id)sender;
|
- (IBAction)nameDidChange:(id)sender;
|
||||||
- (void)resourceAttributesDidChange:(NSNotification *)notification;
|
- (void)resourceAttributesDidChange:(NSNotification *)notification;
|
||||||
- (void)documentInfoDidChange:(NSNotification *)notification;
|
- (void)documentInfoDidChange:(NSNotification *)notification;
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ enum Attributes
|
|||||||
@interface NSWindowController (InfoWindowAdditions)
|
@interface NSWindowController (InfoWindowAdditions)
|
||||||
|
|
||||||
/*! @function resource
|
/*! @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;
|
- (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 <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 "ResourceDocument.h"
|
||||||
#import "Resource.h"
|
#import "Resource.h"
|
||||||
|
#import "ApplicationDelegate.h"
|
||||||
#import "NSOutlineView-SelectedItems.h"
|
#import "NSOutlineView-SelectedItems.h"
|
||||||
#import "MoreFilesX.h"
|
#import "MoreFilesX.h"
|
||||||
|
|
||||||
@implementation InfoWindowController
|
@implementation InfoWindowController
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
|
||||||
self = [self initWithWindowNibName:@"InfoWindow"];
|
|
||||||
if( self ) [self setWindowFrameAutosaveName:@"InfoWindow"];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
@ -40,6 +34,13 @@
|
|||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentInfoDidChange:) name:DocumentInfoDidChangeNotification object:nil];
|
[[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
|
- (void)updateInfoWindow
|
||||||
{
|
{
|
||||||
[nameView setEditable:(selectedResource != nil)];
|
[nameView setEditable:(selectedResource != nil)];
|
||||||
@ -47,16 +48,19 @@
|
|||||||
|
|
||||||
if(selectedResource)
|
if(selectedResource)
|
||||||
{
|
{
|
||||||
[[self window] setTitle:@"Resource Info"];
|
// set UI values
|
||||||
[placeholderView setContentView:resourceView];
|
[[self window] setTitle:NSLocalizedString(@"Resource Info",nil)];
|
||||||
[nameView setStringValue:[selectedResource name]];
|
[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:changedBox column:0] setState:[[selectedResource attributes] shortValue] & resChanged];
|
||||||
[[attributesMatrix cellAtRow:preloadBox column:0] setState:[[selectedResource attributes] shortValue] & resPreload];
|
[[attributesMatrix cellAtRow:preloadBox column:0] setState:[[selectedResource attributes] shortValue] & resPreload];
|
||||||
[[attributesMatrix cellAtRow:protectedBox column:0] setState:[[selectedResource attributes] shortValue] & resProtected];
|
[[attributesMatrix cellAtRow:protectedBox column:0] setState:[[selectedResource attributes] shortValue] & resProtected];
|
||||||
[[attributesMatrix cellAtRow:lockedBox column:0] setState:[[selectedResource attributes] shortValue] & resLocked];
|
[[attributesMatrix cellAtRow:lockedBox column:0] setState:[[selectedResource attributes] shortValue] & resLocked];
|
||||||
[[attributesMatrix cellAtRow:purgableBox column:0] setState:[[selectedResource attributes] shortValue] & resPurgeable];
|
[[attributesMatrix cellAtRow:purgableBox column:0] setState:[[selectedResource attributes] shortValue] & resPurgeable];
|
||||||
[[attributesMatrix cellAtRow:systemHeapBox column:0] setState:[[selectedResource attributes] shortValue] & resSysHeap];
|
[[attributesMatrix cellAtRow:systemHeapBox column:0] setState:[[selectedResource attributes] shortValue] & resSysHeap];
|
||||||
|
|
||||||
|
// swap box
|
||||||
|
[placeholderView setContentView:resourceView];
|
||||||
}
|
}
|
||||||
else if(currentDocument != nil)
|
else if(currentDocument != nil)
|
||||||
{
|
{
|
||||||
@ -65,23 +69,41 @@
|
|||||||
FSRef *fileRef = (FSRef *) NewPtrClear(sizeof(FSRef));
|
FSRef *fileRef = (FSRef *) NewPtrClear(sizeof(FSRef));
|
||||||
if(fileRef && [currentDocument fileName])
|
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(!error) FSGetForkSizes(fileRef, &dataLogicalSize, &rsrcLogicalSize);
|
||||||
}
|
}
|
||||||
if(fileRef) DisposePtr((Ptr) fileRef);
|
if(fileRef) DisposePtr((Ptr) fileRef);
|
||||||
|
|
||||||
// set info window elements to correct values
|
// 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"]];
|
[iconView setImage:[NSImage imageNamed:@"Resource file"]];
|
||||||
[nameView setStringValue:[currentDocument fileName]? [[currentDocument fileName] lastPathComponent]:[currentDocument displayName]];
|
[nameView setStringValue:[currentDocument displayName]];
|
||||||
[[filePropertyForm cellAtIndex:0] setStringValue:[currentDocument creator]];
|
}
|
||||||
[[filePropertyForm cellAtIndex:1] setStringValue:[currentDocument type]];
|
[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:2] setObjectValue:[NSNumber numberWithUnsignedLongLong:dataLogicalSize]];
|
||||||
// [[filePropertyForm cellAtIndex:3] setObjectValue:[NSNumber numberWithUnsignedLongLong:rsrcLogicalSize]];
|
// [[filePropertyForm cellAtIndex:3] setObjectValue:[NSNumber numberWithUnsignedLongLong:rsrcLogicalSize]];
|
||||||
[[filePropertyForm cellAtIndex:2] setStringValue:[[NSNumber numberWithUnsignedLongLong:dataLogicalSize] description]];
|
[[filePropertyForm cellAtIndex:2] setStringValue:[[NSNumber numberWithUnsignedLongLong:dataLogicalSize] description]];
|
||||||
[[filePropertyForm cellAtIndex:3] setStringValue:[[NSNumber numberWithUnsignedLongLong:rsrcLogicalSize] description]];
|
[[filePropertyForm cellAtIndex:3] setStringValue:[[NSNumber numberWithUnsignedLongLong:rsrcLogicalSize] description]];
|
||||||
|
|
||||||
|
// swap box
|
||||||
[placeholderView setContentView:documentView];
|
[placeholderView setContentView:documentView];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[iconView setImage:nil];
|
||||||
|
[nameView setStringValue:nil];
|
||||||
|
[placeholderView setContentView:nil];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMainWindow:(NSWindow *)mainWindow
|
- (void)setMainWindow:(NSWindow *)mainWindow
|
||||||
@ -106,8 +128,8 @@
|
|||||||
- (void)selectedResourceChanged:(NSNotification *)notification
|
- (void)selectedResourceChanged:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
if(![[nameView stringValue] isEqualToString:[selectedResource name]])
|
if(![[nameView stringValue] isEqualToString:[selectedResource name]])
|
||||||
[self nameChanged:nameView];
|
[self nameDidChange:nameView];
|
||||||
selectedResource = [[notification object] selectedItem];
|
selectedResource = (Resource *) [[notification object] selectedItem];
|
||||||
[self updateInfoWindow];
|
[self updateInfoWindow];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,15 +146,13 @@
|
|||||||
[selectedResource setAttributes:[NSNumber numberWithShort:number]];
|
[selectedResource setAttributes:[NSNumber numberWithShort:number]];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(IBAction) nameChanged: (id)sender
|
- (IBAction)nameDidChange:(id)sender
|
||||||
{
|
{
|
||||||
[selectedResource setName:[nameView stringValue]];
|
[selectedResource setName:[nameView stringValue]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)resourceAttributesDidChange:(NSNotification *)notification;
|
- (void)resourceAttributesDidChange:(NSNotification *)notification;
|
||||||
{
|
{
|
||||||
if( ![[nameView stringValue] isEqualToString: [selectedResource name]] )
|
|
||||||
[self nameChanged:nameView];
|
|
||||||
[self updateInfoWindow];
|
[self updateInfoWindow];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +160,7 @@
|
|||||||
{
|
{
|
||||||
static InfoWindowController *sharedInfoWindowController = nil;
|
static InfoWindowController *sharedInfoWindowController = nil;
|
||||||
if(!sharedInfoWindowController)
|
if(!sharedInfoWindowController)
|
||||||
sharedInfoWindowController = [[InfoWindowController allocWithZone:[self zone]] init];
|
sharedInfoWindowController = [[InfoWindowController allocWithZone:[self zone]] initWithWindowNibName:@"InfoWindow"];
|
||||||
return sharedInfoWindowController;
|
return sharedInfoWindowController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
#import "NSOutlineView-SelectedItems.h"
|
#import "NSOutlineView-SelectedItems.h"
|
||||||
#import "Resource.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
|
@implementation NameFormatter
|
||||||
|
|
||||||
- (NSString *)stringForObjectValue:(id)obj
|
- (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 <Cocoa/Cocoa.h>
|
||||||
#import "NameFormatter.h"
|
|
||||||
#import "SizeFormatter.h"
|
#import "SizeFormatter.h"
|
||||||
#import "AttributesFormatter.h"
|
#import "AttributesFormatter.h"
|
||||||
|
|
||||||
@ -8,7 +7,7 @@
|
|||||||
@interface OutlineViewDelegate : NSObject
|
@interface OutlineViewDelegate : NSObject
|
||||||
{
|
{
|
||||||
IBOutlet NSWindow *window;
|
IBOutlet NSWindow *window;
|
||||||
IBOutlet NameFormatter *nameFormatter;
|
IBOutlet NSOutlineView *outlineView;
|
||||||
IBOutlet SizeFormatter *sizeFormatter;
|
IBOutlet SizeFormatter *sizeFormatter;
|
||||||
IBOutlet AttributesFormatter *attributesFormatter;
|
IBOutlet AttributesFormatter *attributesFormatter;
|
||||||
}
|
}
|
||||||
@ -18,9 +17,5 @@ int compareResourcesDescending( Resource *r1, Resource *r2, void *context );
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface NSOutlineView (OutlineSortView)
|
@interface RKOutlineView : NSOutlineView
|
||||||
- (void)swapForOutlineSortView;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface OutlineSortView : NSOutlineView
|
|
||||||
@end
|
@end
|
@ -1,11 +1,42 @@
|
|||||||
#import "OutlineViewDelegate.h"
|
#import "OutlineViewDelegate.h"
|
||||||
#import "Resource.h"
|
#import "Resource.h"
|
||||||
|
#import "ResourceDocument.h"
|
||||||
#import "ResourceDataSource.h"
|
#import "ResourceDataSource.h"
|
||||||
#import "ResourceNameCell.h"
|
#import "ResourceNameCell.h"
|
||||||
#import "ApplicationDelegate.h"
|
#import "ApplicationDelegate.h"
|
||||||
|
|
||||||
@implementation OutlineViewDelegate
|
@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
|
- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn
|
||||||
{
|
{
|
||||||
NSArray *newResources;
|
NSArray *newResources;
|
||||||
@ -15,103 +46,148 @@
|
|||||||
NSImage *indicator = [tableView indicatorImageInTableColumn:tableColumn];
|
NSImage *indicator = [tableView indicatorImageInTableColumn:tableColumn];
|
||||||
NSImage *upArrow = [NSTableView _defaultTableHeaderSortImage];
|
NSImage *upArrow = [NSTableView _defaultTableHeaderSortImage];
|
||||||
if(indicator == upArrow)
|
if(indicator == upArrow)
|
||||||
{
|
newResources = [oldResources sortedArrayUsingFunction:compareResourcesAscending context:[tableColumn identifier]];
|
||||||
newResources = [oldResources sortedArrayUsingFunction:compareResourcesAscending context:(void*)[tableColumn identifier]];
|
else newResources = [oldResources sortedArrayUsingFunction:compareResourcesDescending context:[tableColumn identifier]];
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newResources = [oldResources sortedArrayUsingFunction:compareResourcesDescending context:(void*)[tableColumn identifier]];
|
|
||||||
}
|
|
||||||
|
|
||||||
// swap new array for old one
|
// swap new array for old one
|
||||||
[(ResourceDataSource *)[tableView dataSource] setResources:[NSMutableArray arrayWithArray:newResources]];
|
[(ResourceDataSource *)[tableView dataSource] setResources:[NSMutableArray arrayWithArray:newResources]];
|
||||||
[tableView reloadData];
|
[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)
|
int compareResourcesAscending(Resource *r1, Resource *r2, void *context)
|
||||||
{
|
{
|
||||||
NSString *key = (NSString *)context;
|
NSString *key = (NSString *)context;
|
||||||
SEL sel = NSSelectorFromString(key);
|
|
||||||
|
|
||||||
if( [key isEqualToString:@"name"] || [key isEqualToString:@"type"] )
|
|
||||||
{
|
|
||||||
// compare two NSStrings (case-insensitive)
|
// compare two NSStrings (case-insensitive)
|
||||||
return [(NSString *)[r1 performSelector:sel] caseInsensitiveCompare: (NSString *)[r2 performSelector:sel]];
|
if([key isEqualToString:@"name"] || [key isEqualToString:@"type"])
|
||||||
}
|
return [(NSString *)[r1 valueForKey:key] caseInsensitiveCompare:(NSString *)[r2 valueForKey:key]];
|
||||||
else
|
|
||||||
{
|
|
||||||
// compare two NSNumbers (or any other class)
|
// 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)
|
int compareResourcesDescending(Resource *r1, Resource *r2, void *context)
|
||||||
{
|
{
|
||||||
NSString *key = (NSString *)context;
|
NSString *key = (NSString *)context;
|
||||||
SEL sel = NSSelectorFromString(key);
|
|
||||||
|
|
||||||
if( [key isEqualToString:@"name"] || [key isEqualToString:@"type"] )
|
|
||||||
{
|
|
||||||
// compare two NSStrings (case-insensitive)
|
// compare two NSStrings (case-insensitive)
|
||||||
return -1 * [(NSString *)[r1 performSelector:sel] caseInsensitiveCompare: (NSString *)[r2 performSelector:sel]];
|
if([key isEqualToString:@"name"] || [key isEqualToString:@"type"])
|
||||||
}
|
return -1 * [(NSString *)[r1 valueForKey:key] caseInsensitiveCompare: (NSString *)[r2 valueForKey:key]];
|
||||||
else
|
|
||||||
{
|
|
||||||
// compare two NSNumbers (or any other class)
|
// 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
|
- (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
|
- (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];
|
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];
|
else if([identifier isEqualToString:@"attributes"]) [cell setFormatter:attributesFormatter];
|
||||||
|
|
||||||
// set resource icon
|
// set resource icon
|
||||||
if([identifier isEqualToString:@"name"])
|
if([identifier isEqualToString:@"name"])
|
||||||
{
|
{
|
||||||
// [(ResourceNameCell *)cell setImage:[NSImage imageNamed:@"Resource file"]];
|
if(![resource representedFork])
|
||||||
// [(ResourceNameCell *)cell setImage:[[NSWorkspace sharedWorkspace] iconForFileType:[(Resource *)item type]]];
|
[(ResourceNameCell *)cell setImage:[(ApplicationDelegate *)[NSApp delegate] iconForResourceType:[resource type]]];
|
||||||
[(ResourceNameCell *)cell setImage:[[(ApplicationDelegate *)[NSApp delegate] icons] valueForKey:[(Resource *)item type]]];
|
else [(ResourceNameCell *)cell setImage:[(ApplicationDelegate *)[NSApp delegate] iconForResourceType:nil]];
|
||||||
}
|
|
||||||
|
|
||||||
if( row % 2 )
|
if([[resource name] isEqualToString:@""])
|
||||||
{
|
{
|
||||||
[cell setDrawsBackground:NO];
|
if([cell respondsToSelector:@selector(setPlaceholderString:)]) // 10.3+
|
||||||
[cell setBackgroundColor:[NSColor whiteColor]];
|
{
|
||||||
|
// 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
|
else
|
||||||
{
|
{
|
||||||
[cell setDrawsBackground:YES];
|
// pre-10.3, set text colour to grey and set title accordingly
|
||||||
[cell setBackgroundColor:[NSColor colorWithCalibratedRed:0.93 green:0.95 blue:1.0 alpha:1.0]];
|
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
|
// draw alternating blue/white backgrounds (if pre-10.3)
|
||||||
|
if(NSAppKitVersionNumber < 700.0)
|
||||||
@implementation NSOutlineView (OutlineSortView)
|
|
||||||
|
|
||||||
- (void)swapForOutlineSortView
|
|
||||||
{
|
{
|
||||||
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
|
@end
|
||||||
|
|
||||||
@implementation OutlineSortView
|
@implementation RKOutlineView
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method draggingSourceOperationMaskForLocal:
|
||||||
|
*/
|
||||||
|
- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)local
|
||||||
|
{
|
||||||
|
if(local) return NSDragOperationEvery;
|
||||||
|
else return NSDragOperationCopy;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)keyDown:(NSEvent *)event
|
- (void)keyDown:(NSEvent *)event
|
||||||
{
|
{
|
||||||
if( [self selectedRow] != -1 && [[event characters] isEqualToString:[NSString stringWithCString:"\r"]] )
|
int selectedRow = [self selectedRow];
|
||||||
[self editColumn:0 row:[self selectedRow] withEvent:nil select:YES];
|
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];
|
else [super keyDown:event];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,8 +238,15 @@ int compareResourcesDescending( Resource *r1, Resource *r2, void *context )
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method _sendDelegateDidClickColumn:
|
||||||
|
@pending not needed in 10.3+, use existing sort functionality
|
||||||
|
*/
|
||||||
|
|
||||||
//- (void)_sendDelegateDidMouseDownInHeader:(int)columnIndex
|
//- (void)_sendDelegateDidMouseDownInHeader:(int)columnIndex
|
||||||
- (void)_sendDelegateDidClickColumn:(int)columnIndex
|
- (void)_sendDelegateDidClickColumn:(int)columnIndex
|
||||||
|
{
|
||||||
|
// if(NSAppKitVersionNumber < 700.0)
|
||||||
{
|
{
|
||||||
NSTableColumn *tableColumn = [[self tableColumns] objectAtIndex:columnIndex];
|
NSTableColumn *tableColumn = [[self tableColumns] objectAtIndex:columnIndex];
|
||||||
NSImage *indicator = [self indicatorImageInTableColumn:tableColumn];
|
NSImage *indicator = [self indicatorImageInTableColumn:tableColumn];
|
||||||
@ -176,28 +259,22 @@ int compareResourcesDescending( Resource *r1, Resource *r2, void *context )
|
|||||||
[self setIndicatorImage:downArrow inTableColumn:tableColumn];
|
[self setIndicatorImage:downArrow inTableColumn:tableColumn];
|
||||||
else [self setIndicatorImage:upArrow inTableColumn:tableColumn];
|
else [self setIndicatorImage:upArrow inTableColumn:tableColumn];
|
||||||
}
|
}
|
||||||
else
|
else // new column selected
|
||||||
{
|
|
||||||
// new column selected
|
|
||||||
if( [self highlightedTableColumn] != nil )
|
|
||||||
{
|
{
|
||||||
// if there is an existing selection, clear it's image
|
// if there is an existing selection, clear it's image
|
||||||
|
if([self highlightedTableColumn] != nil)
|
||||||
[self setIndicatorImage:nil inTableColumn:[self highlightedTableColumn]];
|
[self setIndicatorImage:nil inTableColumn:[self highlightedTableColumn]];
|
||||||
}
|
|
||||||
|
|
||||||
if( [[tableColumn identifier] isEqualToString:@"name"] || [[tableColumn identifier] isEqualToString:@"type"] )
|
|
||||||
{
|
|
||||||
// sort name and type columns ascending by default
|
// sort name and type columns ascending by default
|
||||||
|
if([[tableColumn identifier] isEqualToString:@"name"] || [[tableColumn identifier] isEqualToString:@"type"])
|
||||||
[self setIndicatorImage:upArrow inTableColumn:tableColumn];
|
[self setIndicatorImage:upArrow inTableColumn:tableColumn];
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// sort all other columns descending by default
|
// sort all other columns descending by default
|
||||||
[self setIndicatorImage:downArrow inTableColumn:tableColumn];
|
else [self setIndicatorImage:downArrow inTableColumn:tableColumn];
|
||||||
}
|
|
||||||
[self setHighlightedTableColumn:tableColumn];
|
[self setHighlightedTableColumn:tableColumn];
|
||||||
}
|
}
|
||||||
[[self delegate] tableView:self didClickTableColumn:tableColumn];
|
[[self delegate] tableView:self didClickTableColumn:tableColumn];
|
||||||
}
|
}
|
||||||
|
// else [super _sendDelegateDidClickColumn:columnIndex];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
@ -1,6 +1,8 @@
|
|||||||
#import "PasteboardDocument.h"
|
#import "PasteboardDocument.h"
|
||||||
#import "Resource.h"
|
#import "Resource.h"
|
||||||
|
|
||||||
|
extern NSString *RKResourcePboardType;
|
||||||
|
|
||||||
@implementation PasteboardDocument
|
@implementation PasteboardDocument
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
@ -15,32 +17,36 @@
|
|||||||
|
|
||||||
-(void)readPasteboard:(NSString *)pbName
|
-(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];
|
NSPasteboard *pb = [NSPasteboard pasteboardWithName:pbName];
|
||||||
NSArray *types = [pb types];
|
NSEnumerator *enumerator = [[pb types] objectEnumerator];
|
||||||
NSEnumerator *enumerator = [types objectEnumerator];
|
NSString *pbType;
|
||||||
NSString *currentType;
|
|
||||||
|
|
||||||
|
// 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];
|
[[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
|
// 'paste' any resources into pbdoc's data source
|
||||||
NSString *name = pbName;
|
if( [pbType isEqualToString:RKResourcePboardType] )
|
||||||
NSString *type;
|
[self pasteResources:[NSUnarchiver unarchiveObjectWithData:[pb dataForType:RKResourcePboardType]]];
|
||||||
NSNumber *resID;
|
else
|
||||||
NSNumber *attributes;
|
{
|
||||||
NSData *data;
|
// create the faux resource & add it to the array
|
||||||
Resource *resource;
|
Resource *resource = [Resource resourceOfType:nil andID:nil withName:pbType andAttributes:nil data:[pb dataForType:pbType]];
|
||||||
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];
|
|
||||||
[resources addObject:resource]; // array retains resource
|
[resources addObject:resource]; // array retains resource
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-enable undos
|
||||||
[[self undoManager] enableUndoRegistration];
|
[[self undoManager] enableUndoRegistration];
|
||||||
|
|
||||||
[outlineView reloadData];
|
[outlineView reloadData];
|
||||||
|
@ -31,10 +31,3 @@ enum LaunchAction
|
|||||||
+ (id)sharedPrefsWindowController;
|
+ (id)sharedPrefsWindowController;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface NSString (BooleanSupport)
|
|
||||||
|
|
||||||
- (BOOL)boolValue;
|
|
||||||
+ (NSString *)stringWithBool:(BOOL)boolean;
|
|
||||||
|
|
||||||
@end
|
|
@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
self = [self initWithWindowNibName:@"PrefsWindow"];
|
return [self initWithWindowNibName:@"PrefsWindow"];
|
||||||
if( self ) [self setWindowFrameAutosaveName:@"ResKnife Preferences"];
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
@ -19,6 +17,7 @@
|
|||||||
{
|
{
|
||||||
// represent current prefs in window state
|
// represent current prefs in window state
|
||||||
[self updatePrefs:nil];
|
[self updatePrefs:nil];
|
||||||
|
[[self window] center];
|
||||||
|
|
||||||
// listen out for pref changes from elsewhere
|
// listen out for pref changes from elsewhere
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatePrefs:) name:NSUserDefaultsDidChangeNotification object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatePrefs:) name:NSUserDefaultsDidChangeNotification object:nil];
|
||||||
@ -101,26 +100,9 @@
|
|||||||
+ (id)sharedPrefsWindowController
|
+ (id)sharedPrefsWindowController
|
||||||
{
|
{
|
||||||
static PrefsWindowController *sharedPrefsWindowController = nil;
|
static PrefsWindowController *sharedPrefsWindowController = nil;
|
||||||
|
|
||||||
if( !sharedPrefsWindowController )
|
if( !sharedPrefsWindowController )
|
||||||
{
|
|
||||||
sharedPrefsWindowController = [[PrefsWindowController allocWithZone:[self zone]] init];
|
sharedPrefsWindowController = [[PrefsWindowController allocWithZone:[self zone]] init];
|
||||||
}
|
|
||||||
return sharedPrefsWindowController;
|
return sharedPrefsWindowController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@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 "RKDocumentController.h"
|
||||||
#import "ApplicationDelegate.h"
|
#import "ApplicationDelegate.h"
|
||||||
#import "OpenFileDataSource.h"
|
#import "OpenPanelDelegate.h"
|
||||||
|
|
||||||
@implementation RKDocumentController
|
@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
|
- (int)runModalOpenPanel:(NSOpenPanel *)openPanel forTypes:(NSArray *)extensions
|
||||||
{
|
{
|
||||||
[openPanel setAccessoryView:[(ApplicationDelegate *)[NSApp delegate] openAuxView]];
|
// set-up open panel (this happens every time, but no harm done)
|
||||||
return [super runModalOpenPanel:openPanel forTypes:extensions];
|
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
|
@end
|
||||||
|
@ -32,13 +32,12 @@
|
|||||||
|
|
||||||
@interface RKEditorRegistry : NSObject
|
@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.
|
- (IBAction)scanForPlugins:(id)sender; // Called automatically by mainRegistry.
|
||||||
- (Class)editorForType:(NSString *)typeStr; // You probably want to call this.
|
- (Class)editorForType:(NSString *)typeStr; // You probably want to call this.
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -22,131 +22,160 @@
|
|||||||
-------------------------------------------------------------------------- */
|
-------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#import "RKEditorRegistry.h"
|
#import "RKEditorRegistry.h"
|
||||||
|
#import "RKSupportResourceRegistry.h"
|
||||||
|
#import "NSString-FSSpec.h" // for ResKnifeBoolExtensions (in wrong file)
|
||||||
|
|
||||||
|
/*!
|
||||||
/* -----------------------------------------------------------------------------
|
@class RKEditorRegistry
|
||||||
Globals:
|
@author Uli Kusterer
|
||||||
-------------------------------------------------------------------------- */
|
@created 2003-07-31
|
||||||
|
@description This is a registry where all our resource-editor plugins are looked
|
||||||
RKEditorRegistry* gRKEditorRegistryMainRegistry = nil; // Access through +mainRegistry!
|
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
|
@implementation RKEditorRegistry
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/*!
|
||||||
mainRegistry:
|
@method +defaultRegistry
|
||||||
Returns the main plugin registry of this application, instantiating
|
@author Uli Kusterer
|
||||||
it first if there is none yet. As soon as this is instantiated, the
|
@created 2003-07-31
|
||||||
plugins are loaded.
|
@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.
|
||||||
REVISIONS:
|
*/
|
||||||
2003-07-31 UK Created.
|
+ (RKEditorRegistry *)defaultRegistry
|
||||||
-------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
+(RKEditorRegistry*) mainRegistry
|
|
||||||
{
|
{
|
||||||
if( !gRKEditorRegistryMainRegistry )
|
static RKEditorRegistry *defaultRegistry = nil;
|
||||||
|
if(!defaultRegistry)
|
||||||
{
|
{
|
||||||
gRKEditorRegistryMainRegistry = [[RKEditorRegistry alloc] init];
|
defaultRegistry = [[RKEditorRegistry alloc] init];
|
||||||
[gRKEditorRegistryMainRegistry scanForPlugins: gRKEditorRegistryMainRegistry];
|
[defaultRegistry scanForPlugins:nil];
|
||||||
}
|
}
|
||||||
return gRKEditorRegistryMainRegistry;
|
return defaultRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
/* -----------------------------------------------------------------------------
|
@method awakeFromNib
|
||||||
awakeFromNib:
|
@abstract Makes sure that if an instance of this is instantiated from a nib file, it automatically loads the plugins.
|
||||||
Makes sure that if an instance of this is instantiated from a NIB file,
|
@author Uli Kusterer
|
||||||
it automatically loads the plugins.
|
@created 2003-07-31
|
||||||
|
*/
|
||||||
REVISIONS:
|
|
||||||
2003-07-31 UK Created.
|
|
||||||
-------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
- (void)awakeFromNib
|
- (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.
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
@description This scans the application's internal Plugins folder,
|
||||||
scanForPlugins:
|
<tt>~/Library/Application Support/ResKnife/Plugins/</tt> and
|
||||||
(Re)loads our list of plugins. You can use this as an action for a menu
|
<tt>/Library/Application Support/ResKnife/Plugins/</tt> for
|
||||||
item, if you want.
|
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,
|
<p>It builds a registry of Class objects in an NSMutableDictionary,
|
||||||
~/Library/Application Support/ResKnife/Plugins/ and
|
where the key is the resource type. If a plugin supports several
|
||||||
/Library/Application Support/ResKnife/Plugins/ for plugins that have
|
resource types (as indicated by the RKEditedTypes key in it's
|
||||||
the extension ".plugin" and implement initWithResource: (which means
|
Info.plist), it will be registered for these types as well.
|
||||||
this won't get into the way if you want to support other kinds of
|
If several plugins register for the same type, the last one
|
||||||
plugins).
|
loaded wins.</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 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>To instantiate an object from a plugin, see <tt>editorForType:</tt>
|
||||||
|
*/
|
||||||
- (IBAction)scanForPlugins:(id)sender
|
- (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 *appSupport = @"Library/Application Support/ResKnife/Plugins/";
|
||||||
NSString *appPath = [[NSBundle mainBundle] builtInPlugInsPath];
|
NSString *appPath = [[NSBundle mainBundle] builtInPlugInsPath];
|
||||||
NSString *userPath = [NSHomeDirectory() stringByAppendingPathComponent:appSupport];
|
NSString *userPath = [NSHomeDirectory() stringByAppendingPathComponent:appSupport];
|
||||||
NSString *sysPath = [@"/" stringByAppendingPathComponent:appSupport];
|
NSString *sysPath = [@"/" stringByAppendingPathComponent:appSupport];
|
||||||
NSArray *paths = [NSArray arrayWithObjects:appPath, userPath, sysPath, nil];
|
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory, NSAllDomainsMask, YES);
|
||||||
NSEnumerator *pathEnum = [paths objectEnumerator];
|
NSEnumerator *pathEnumerator = [[NSArray arrayWithObjects:appPath, userPath, sysPath, nil] objectEnumerator];
|
||||||
NSString *path;
|
NSString *path;
|
||||||
|
|
||||||
if( typeRegistry )
|
// release any existing registry to clear old values
|
||||||
[typeRegistry release];
|
if(typeRegistry) [typeRegistry release];
|
||||||
typeRegistry = [[NSMutableDictionary alloc] init];
|
typeRegistry = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
while( path = [pathEnum nextObject] )
|
// scan all paths
|
||||||
|
while(path = [pathEnumerator nextObject])
|
||||||
{
|
{
|
||||||
NSEnumerator *e = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
|
NSEnumerator *fileEnumerator = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
|
||||||
NSString *name;
|
NSString *pluginName;
|
||||||
|
|
||||||
while( name = [e nextObject] )
|
// enumerate all files in this directory
|
||||||
|
while(pluginName = [fileEnumerator nextObject])
|
||||||
{
|
{
|
||||||
name = [path stringByAppendingPathComponent:name];
|
NSString *pluginPath = [path stringByAppendingPathComponent:pluginName];
|
||||||
NSLog(@"Examining %@", name);
|
// NSLog(@"Examining %@", pluginPath);
|
||||||
if( [[name pathExtension] isEqualToString:@"plugin"] )
|
|
||||||
{
|
|
||||||
NSBundle *plugin = [NSBundle bundleWithPath: name];
|
|
||||||
|
|
||||||
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;
|
NSString *resType;
|
||||||
NSArray *types = [[plugin infoDictionary] objectForKey:@"RKEditedTypes"];
|
|
||||||
NSEnumerator *enny;
|
NSEnumerator *enny;
|
||||||
|
supportedTypes = [[plugin infoDictionary] objectForKey:@"RKEditedTypes"];
|
||||||
|
if(supportedTypes == nil)
|
||||||
|
supportedTypes = [NSArray arrayWithObject: [[plugin infoDictionary] objectForKey:@"RKEditedType"]];
|
||||||
|
|
||||||
if( types == nil )
|
for(enny = [supportedTypes objectEnumerator]; resType = [enny nextObject];)
|
||||||
types = [NSArray arrayWithObject: [[plugin infoDictionary] objectForKey:@"RKEditedType"]];
|
|
||||||
|
|
||||||
for( enny = [types objectEnumerator]; resType = [enny nextObject]; )
|
|
||||||
{
|
{
|
||||||
[typeRegistry setObject:pluginClass forKey:resType];
|
[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)editorForType:(NSString *)typeStr
|
||||||
{
|
{
|
||||||
Class theClass = [typeRegistry objectForKey: typeStr];
|
Class theClass = [typeRegistry objectForKey: typeStr];
|
||||||
if( !theClass )
|
if(!theClass) return Nil;
|
||||||
return Nil;
|
else return theClass;
|
||||||
|
|
||||||
return theClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -11,10 +11,7 @@
|
|||||||
|
|
||||||
@interface RKSupportResourceRegistry : NSObject
|
@interface RKSupportResourceRegistry : NSObject
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
+ (void)scanForSupportResources;
|
||||||
+(void) scanForSupportResources: (NSDocumentController*)c;
|
+ (void)scanForSupportResourcesInFolder:(NSString *)path;
|
||||||
|
|
||||||
|
|
||||||
@end
|
@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 "RKSupportResourceRegistry.h"
|
||||||
|
#import "NGSCategories.h"
|
||||||
|
|
||||||
@implementation RKSupportResourceRegistry
|
@implementation RKSupportResourceRegistry
|
||||||
|
|
||||||
+(void) scanForSupportResources: (NSDocumentController*)c
|
+ (void)scanForSupportResources
|
||||||
{
|
{
|
||||||
// TODO: Instead of hard-coding sysPath we should use some FindFolder-like API!
|
// TODO: Instead of hard-coding sysPath we should use some FindFolder-like API!
|
||||||
NSString *appSupport = @"Library/Application Support/ResKnife/Support Resources/";
|
#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED
|
||||||
NSString *appPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Support Resources"];
|
NSArray *dirsArray = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSAllDomainsMask, YES);
|
||||||
NSString *userPath = [NSHomeDirectory() stringByAppendingPathComponent:appSupport];
|
dirsArray = [dirsArray arrayByMakingObjectsPerformSelector:@selector(stringByAppendingPathComponent:) withObject:@"ResKnife/Support Resources"];
|
||||||
NSString *sysPath = [@"/" stringByAppendingPathComponent:appSupport];
|
#endif
|
||||||
NSArray *paths = [NSArray arrayWithObjects:appPath, userPath, sysPath, nil];
|
[RKSupportResourceRegistry scanForSupportResourcesInFolder:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Support Resources"]];
|
||||||
NSEnumerator *pathEnum = [paths objectEnumerator];
|
[RKSupportResourceRegistry scanForSupportResourcesInFolder:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/ResKnife/Support Resources"]];
|
||||||
NSString *path;
|
[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;
|
NSString *name;
|
||||||
|
NSEnumerator *enumerator = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
|
||||||
NSLog(@"Looking for resources in %@", path);
|
while(name = [enumerator nextObject])
|
||||||
|
|
||||||
while( name = [e nextObject] )
|
|
||||||
{
|
{
|
||||||
name = [path stringByAppendingPathComponent:name];
|
// NSLog(@"Examining %@", name);
|
||||||
NSLog(@"Examining %@", name);
|
|
||||||
if([[name pathExtension] isEqualToString:@"rsrc"])
|
if([[name pathExtension] isEqualToString:@"rsrc"])
|
||||||
{
|
// FIXME: this method was deprecate in 10.4 in favour of - (id)openDocumentWithContentsOfURL:(NSURL *)absoluteURL display:(BOOL)displayDocument error:(NSError **)outError;
|
||||||
[c openDocumentWithContentsOfFile:name display:YES];
|
[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfFile:[path stringByAppendingPathComponent:name] display:YES];
|
||||||
//[[[[[c openDocumentWithContentsOfFile:name display:YES] windowControllers] objectAtIndex:0] window] orderOut: self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#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>
|
@interface Resource : NSObject <NSCopying, NSCoding, ResKnifeResourceProtocol>
|
||||||
{
|
{
|
||||||
@ -17,13 +24,16 @@
|
|||||||
// the actual data
|
// the actual data
|
||||||
NSData *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
|
// accessor methods not part of the protocol
|
||||||
|
- (void)_setName:(NSString *)newName;
|
||||||
- (void)setDirty:(BOOL)newValue;
|
- (void)setDirty:(BOOL)newValue;
|
||||||
- (NSString *)representedFork;
|
- (NSString *)representedFork;
|
||||||
- (void)setRepresentedFork:(NSString *)forkName;
|
- (void)setRepresentedFork:(NSString *)forkName;
|
||||||
|
- (void)setDocumentName:(NSString *)docName;
|
||||||
|
|
||||||
// init methods
|
// init methods
|
||||||
- (id)initWithType:(NSString *)typeValue andID:(NSNumber *)resIDValue;
|
- (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;
|
||||||
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue data:(NSData *)dataValue;
|
+ (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
|
@end
|
||||||
|
@ -58,13 +58,13 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
return [resource autorelease];
|
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;
|
NSDocument *doc;
|
||||||
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
||||||
while(doc = [enumerator nextObject])
|
while(doc = [enumerator nextObject])
|
||||||
{
|
{
|
||||||
if( document == nil || document == doc )
|
if(searchDoc == nil || searchDoc == doc)
|
||||||
{
|
{
|
||||||
// parse document for correct resource
|
// parse document for correct resource
|
||||||
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue andID:resIDValue];
|
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue andID:resIDValue];
|
||||||
@ -76,7 +76,7 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
|
|
||||||
/* ResKnifeResourceProtocol implementation */
|
/* ResKnifeResourceProtocol implementation */
|
||||||
|
|
||||||
+ (NSArray *)allResourcesOfType:(NSString *)typeValue inDocument:(NSDocument *)document
|
+ (NSArray *)allResourcesOfType:(NSString *)typeValue inDocument:(NSDocument *)searchDoc
|
||||||
{
|
{
|
||||||
NSMutableArray *array = [NSMutableArray array];
|
NSMutableArray *array = [NSMutableArray array];
|
||||||
NSDocument *doc;
|
NSDocument *doc;
|
||||||
@ -84,19 +84,19 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
while(doc = [enumerator nextObject])
|
while(doc = [enumerator nextObject])
|
||||||
{
|
{
|
||||||
// parse document for resources
|
// parse document for resources
|
||||||
if( document == nil || document == doc )
|
if(searchDoc == nil || searchDoc == doc)
|
||||||
[array addObjectsFromArray:[[(ResourceDocument *)doc dataSource] allResourcesOfType:typeValue]];
|
[array addObjectsFromArray:[[(ResourceDocument *)doc dataSource] allResourcesOfType:typeValue]];
|
||||||
}
|
}
|
||||||
return [NSArray arrayWithArray:array];
|
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;
|
NSDocument *doc;
|
||||||
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
||||||
while(doc = [enumerator nextObject])
|
while(doc = [enumerator nextObject])
|
||||||
{
|
{
|
||||||
if( document == nil || document == doc )
|
if(searchDoc == nil || searchDoc == doc)
|
||||||
{
|
{
|
||||||
// parse document for correct resource
|
// parse document for correct resource
|
||||||
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue withName:nameValue];
|
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue withName:nameValue];
|
||||||
@ -106,13 +106,13 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue inDocument:(NSDocument *)document
|
+ (Resource *)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue inDocument:(NSDocument *)searchDoc
|
||||||
{
|
{
|
||||||
NSDocument *doc;
|
NSDocument *doc;
|
||||||
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
NSEnumerator *enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
|
||||||
while(doc = [enumerator nextObject])
|
while(doc = [enumerator nextObject])
|
||||||
{
|
{
|
||||||
if( document == nil || document == doc )
|
if(searchDoc == nil || searchDoc == doc)
|
||||||
{
|
{
|
||||||
// parse document for correct resource
|
// parse document for correct resource
|
||||||
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue andID:resIDValue];
|
Resource *resource = [[(ResourceDocument *)doc dataSource] resourceOfType:typeValue andID:resIDValue];
|
||||||
@ -122,6 +122,24 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
return nil;
|
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
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
[representedFork release];
|
[representedFork release];
|
||||||
@ -130,16 +148,18 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
[resID release];
|
[resID release];
|
||||||
[attributes release];
|
[attributes release];
|
||||||
[data release];
|
[data release];
|
||||||
|
[_docName release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)copyWithZone:(NSZone *)zone
|
- (id)copyWithZone:(NSZone *)zone
|
||||||
{
|
{
|
||||||
Resource *copy = [[Resource alloc] initWithType:type andID:resID withName:name andAttributes:attributes data:[data copy]];
|
Resource *copy = [[Resource alloc] initWithType:type andID:resID withName:name andAttributes:attributes data:[data copy]];
|
||||||
|
[copy setDocumentName:_docName];
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accessors */
|
/* accessors */
|
||||||
|
|
||||||
- (void)touch
|
- (void)touch
|
||||||
{
|
{
|
||||||
@ -157,18 +177,15 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDidChangeNotification object:self];
|
[[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
|
- (NSDocument *)document
|
||||||
{
|
{
|
||||||
return document;
|
return [Resource documentForResource:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setDocumentName:(NSString *)docName
|
||||||
|
{
|
||||||
|
_docName = [docName copy];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *)representedFork
|
- (NSString *)representedFork
|
||||||
{
|
{
|
||||||
@ -185,6 +202,14 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
return name;
|
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
|
- (void)setName:(NSString *)newName
|
||||||
{
|
{
|
||||||
if(![name isEqualToString:newName])
|
if(![name isEqualToString:newName])
|
||||||
@ -192,24 +217,22 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceNameWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceNameWillChangeNotification object:self];
|
||||||
|
|
||||||
[name autorelease];
|
id old = name;
|
||||||
name = [newName copy];
|
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];
|
[self setDirty:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)defaultWindowTitle
|
||||||
-(NSString*) nameForEditorWindow
|
|
||||||
{
|
{
|
||||||
if( [name length] > 0 )
|
if([name length] > 0) return [NSString stringWithFormat: NSLocalizedString(@"%@: %@ %@ '%@'", @"default window title format with resource name"), _docName, type, resID, name];
|
||||||
return [NSString stringWithFormat: @"%@: '%@' ID=%@ \"%@\"", [document displayName], type, resID, name];
|
else return [NSString stringWithFormat: NSLocalizedString(@"%@: %@ %@", @"default window title format without resource name"), _docName, type, resID];
|
||||||
else
|
|
||||||
return [NSString stringWithFormat: @"%@: '%@' ID=%@", [document displayName], type, resID];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSString *)type
|
- (NSString *)type
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
@ -222,10 +245,12 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceTypeWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceTypeWillChangeNotification object:self];
|
||||||
|
|
||||||
[type autorelease];
|
id old = type;
|
||||||
type = [newType copy];
|
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];
|
[self setDirty:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,10 +267,12 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceIDWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceIDWillChangeNotification object:self];
|
||||||
|
|
||||||
[resID autorelease];
|
id old = resID;
|
||||||
resID = [newResID copy];
|
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];
|
[self setDirty:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,10 +289,12 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillChangeNotification object:self];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceAttributesWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceAttributesWillChangeNotification object:self];
|
||||||
|
|
||||||
[attributes autorelease];
|
id old = attributes;
|
||||||
attributes = [newAttributes copy];
|
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];
|
[self setDirty:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,8 +317,9 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDataWillChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDataWillChangeNotification object:self];
|
||||||
|
|
||||||
// note: this function retains, rather than copies, the supplied data
|
// note: this function retains, rather than copies, the supplied data
|
||||||
[data autorelease];
|
id old = data;
|
||||||
data = [newData retain];
|
data = [newData retain];
|
||||||
|
[old release];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDataDidChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDataDidChangeNotification object:self];
|
||||||
[self setDirty:YES];
|
[self setDirty:YES];
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
@class ResourceDocument, Resource;
|
@class ResourceDocument, Resource;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@class ResourceDataSource
|
||||||
|
@pending This class needs to be made KVC compliant.
|
||||||
|
*/
|
||||||
|
|
||||||
@interface ResourceDataSource : NSObject
|
@interface ResourceDataSource : NSObject
|
||||||
{
|
{
|
||||||
IBOutlet NSOutlineView *outlineView;
|
IBOutlet NSOutlineView *outlineView;
|
||||||
@ -11,18 +16,59 @@
|
|||||||
NSMutableArray *resources;
|
NSMutableArray *resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method window
|
||||||
|
*/
|
||||||
- (NSWindow *)window;
|
- (NSWindow *)window;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method resources
|
||||||
|
*/
|
||||||
- (NSArray *)resources;
|
- (NSArray *)resources;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method setResources:
|
||||||
|
*/
|
||||||
- (void)setResources:(NSMutableArray *)newResources;
|
- (void)setResources:(NSMutableArray *)newResources;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method addResource:
|
||||||
|
*/
|
||||||
- (void)addResource:(Resource *)resource;
|
- (void)addResource:(Resource *)resource;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method removeResource:
|
||||||
|
*/
|
||||||
- (void)removeResource:(Resource *)resource;
|
- (void)removeResource:(Resource *)resource;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method uniqueIDForType:
|
||||||
|
*/
|
||||||
- (NSNumber *)uniqueIDForType:(NSString *)type;
|
- (NSNumber *)uniqueIDForType:(NSString *)type;
|
||||||
|
|
||||||
// accessors
|
/*!
|
||||||
|
@method defaultIDForType:
|
||||||
|
*/
|
||||||
|
- (NSNumber *)defaultIDForType:(NSString *)type;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method resourceOfType:andID:
|
||||||
|
*/
|
||||||
- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID;
|
- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method resourceOfType:withName:
|
||||||
|
*/
|
||||||
- (Resource *)resourceOfType:(NSString *)type withName:(NSString *)name;
|
- (Resource *)resourceOfType:(NSString *)type withName:(NSString *)name;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method allResourcesOfType:
|
||||||
|
*/
|
||||||
- (NSArray *)allResourcesOfType:(NSString *)type;
|
- (NSArray *)allResourcesOfType:(NSString *)type;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method allResourceIDsOfType:
|
||||||
|
*/
|
||||||
- (NSArray *)allResourceIDsOfType:(NSString *)type;
|
- (NSArray *)allResourceIDsOfType:(NSString *)type;
|
||||||
|
|
||||||
|
|
||||||
@end
|
@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 "ResourceDataSource.h"
|
||||||
#import "ResourceDocument.h"
|
#import "ResourceDocument.h"
|
||||||
#import "Resource.h"
|
#import "Resource.h"
|
||||||
#import <limits.h>
|
#import <limits.h>
|
||||||
|
|
||||||
|
NSString *DataSourceWillAddResourceNotification = @"DataSourceWillAddResource";
|
||||||
|
NSString *DataSourceDidAddResourceNotification = @"DataSourceDidAddResource";
|
||||||
|
NSString *DataSourceWillRemoveResourceNotification = @"DataSourceWillRemoveResource";
|
||||||
|
NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResource";
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
extern NSString *RKResourcePboardType;
|
||||||
Notification names:
|
|
||||||
-------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
NSString *DataSourceWillAddResourceNotification = @"DataSourceWillAddResourceNotification";
|
|
||||||
NSString *DataSourceDidAddResourceNotification = @"DataSourceDidAddResourceNotification";
|
|
||||||
NSString *DataSourceWillRemoveResourceNotification = @"DataSourceWillRemoveResourceNotification";
|
|
||||||
NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourceNotification";
|
|
||||||
|
|
||||||
@implementation ResourceDataSource
|
@implementation ResourceDataSource
|
||||||
|
|
||||||
@ -60,8 +37,9 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
|||||||
|
|
||||||
- (void)setResources:(NSMutableArray *)newResources
|
- (void)setResources:(NSMutableArray *)newResources
|
||||||
{
|
{
|
||||||
[resources autorelease];
|
id old = resources;
|
||||||
resources = [newResources retain];
|
resources = [newResources retain];
|
||||||
|
[old release];
|
||||||
[outlineView reloadData];
|
[outlineView reloadData];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +49,7 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:DataSourceWillAddResourceNotification object:dictionary];
|
[[NSNotificationCenter defaultCenter] postNotificationName:DataSourceWillAddResourceNotification object:dictionary];
|
||||||
|
|
||||||
// it seems very inefficient to reload the entire data source when just adding/removing one item
|
// 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
|
// for large resource files, the data source gets reloaded hundreds of times upon load
|
||||||
[resource setDocument:document];
|
|
||||||
[resources addObject:resource];
|
[resources addObject:resource];
|
||||||
[outlineView reloadData];
|
[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
|
[[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
|
- (void)resourceDidChange:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
// reload the data for the changed resource
|
// reload the data for the changed resource
|
||||||
[outlineView reloadItem:[notification object]];
|
[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 */
|
/* Data source protocol implementation */
|
||||||
@ -141,10 +107,11 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
|||||||
#pragma unused(outlineView)
|
#pragma unused(outlineView)
|
||||||
NSString *identifier = [tableColumn identifier];
|
NSString *identifier = [tableColumn identifier];
|
||||||
if([identifier isEqualToString:@"resID"])
|
if([identifier isEqualToString:@"resID"])
|
||||||
[item takeValue:[NSNumber numberWithInt:[object intValue]] forKey:identifier];
|
[item setValue:[NSNumber numberWithInt:[object intValue]] forKey:identifier];
|
||||||
else [item takeValue:object forKey:identifier];
|
else [item setValue:object forKey:identifier];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
/* ACCESSORS */
|
/* ACCESSORS */
|
||||||
|
|
||||||
- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID
|
- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID
|
||||||
@ -184,18 +151,17 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
|||||||
return [NSArray arrayWithArray:array];
|
return [NSArray arrayWithArray:array];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
/* -----------------------------------------------------------------------------
|
@method allResourceIDsOfType:
|
||||||
allResourceIDsOfType:
|
@discussion Returns an NSArray full of NSNumber* objects containing the IDs of all resources of specified type. Used by uniqueIDForType:.
|
||||||
Returns an NSArray full of NSNumber* objects containing the IDs of all
|
@updated 2003-08-01 UK Created based on allResourcesOfType:
|
||||||
resources of specified type. Used by uniqueIDForType:.
|
*/
|
||||||
|
|
||||||
REVISIONS:
|
|
||||||
2003-08-01 UK Created based on allResourcesOfType:.
|
|
||||||
-------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
- (NSArray*)allResourceIDsOfType:(NSString *)type
|
- (NSArray*)allResourceIDsOfType:(NSString *)type
|
||||||
{
|
{
|
||||||
|
if(!type || [type isEqualToString:@""])
|
||||||
|
return [NSArray array];
|
||||||
|
|
||||||
Resource *resource;
|
Resource *resource;
|
||||||
NSMutableArray *array = [NSMutableArray array];
|
NSMutableArray *array = [NSMutableArray array];
|
||||||
NSEnumerator *enumerator = [resources objectEnumerator];
|
NSEnumerator *enumerator = [resources objectEnumerator];
|
||||||
@ -207,22 +173,16 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
|||||||
return [NSArray arrayWithArray:array];
|
return [NSArray arrayWithArray:array];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
/* -----------------------------------------------------------------------------
|
@method uniqueIDForType:
|
||||||
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.
|
||||||
Tries to return an unused resource ID for a new resource of specified
|
@updated 2003-08-01 UK: Created.
|
||||||
type. If all IDs are used up (can't really happen, because the resource
|
@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)
|
||||||
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.
|
|
||||||
-------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
- (NSNumber *)uniqueIDForType:(NSString *)type
|
- (NSNumber *)uniqueIDForType:(NSString *)type
|
||||||
{
|
{
|
||||||
short theID = 128;
|
short theID = [[self defaultIDForType:type] shortValue];
|
||||||
NSArray *array = [self allResourceIDsOfType:type];
|
NSArray *array = [self allResourceIDsOfType:type];
|
||||||
|
|
||||||
if([array count] <= USHRT_MAX)
|
if([array count] <= USHRT_MAX)
|
||||||
@ -234,4 +194,54 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
|||||||
return [NSNumber numberWithShort: theID];
|
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
|
@end
|
||||||
|
@ -12,10 +12,20 @@
|
|||||||
NSMutableDictionary *toolbarItems;
|
NSMutableDictionary *toolbarItems;
|
||||||
NSMutableArray *resources;
|
NSMutableArray *resources;
|
||||||
HFSUniStr255 *fork; // name of fork to save to, usually empty string (data fork) or 'RESOURCE_FORK' as returned from FSGetResourceForkName()
|
HFSUniStr255 *fork; // name of fork to save to, usually empty string (data fork) or 'RESOURCE_FORK' as returned from FSGetResourceForkName()
|
||||||
NSString *creator;
|
NSData *creator;
|
||||||
NSString *type;
|
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;
|
- (void)setupToolbar:(NSWindowController *)windowController;
|
||||||
|
|
||||||
- (IBAction)showCreateResourceSheet:(id)sender;
|
- (IBAction)showCreateResourceSheet:(id)sender;
|
||||||
@ -29,9 +39,6 @@
|
|||||||
- (IBAction)playSound:(id)sender;
|
- (IBAction)playSound:(id)sender;
|
||||||
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished;
|
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished;
|
||||||
|
|
||||||
-(IBAction) exportResourceToFile: (id)sender;
|
|
||||||
-(IBAction) exportResourceToImageFile: (id)sender;
|
|
||||||
|
|
||||||
- (IBAction)copy:(id)sender;
|
- (IBAction)copy:(id)sender;
|
||||||
- (IBAction)paste:(id)sender;
|
- (IBAction)paste:(id)sender;
|
||||||
- (void)pasteResources:(NSArray *)pastedResources;
|
- (void)pasteResources:(NSArray *)pastedResources;
|
||||||
@ -45,21 +52,17 @@
|
|||||||
- (void)resourceTypeWillChange:(NSNotification *)notification;
|
- (void)resourceTypeWillChange:(NSNotification *)notification;
|
||||||
- (void)resourceAttributesWillChange:(NSNotification *)notification;
|
- (void)resourceAttributesWillChange:(NSNotification *)notification;
|
||||||
|
|
||||||
- (BOOL)readFork:(NSString *)forkName asStreamFromFile:(NSString *)fileName;
|
|
||||||
- (BOOL)readResourceMap:(SInt16)fileRefNum;
|
|
||||||
- (BOOL)writeResourceMap:(SInt16)fileRefNum;
|
|
||||||
|
|
||||||
- (NSWindow *)mainWindow;
|
- (NSWindow *)mainWindow;
|
||||||
- (ResourceDataSource *)dataSource;
|
- (ResourceDataSource *)dataSource;
|
||||||
- (NSOutlineView *)outlineView;
|
- (NSOutlineView *)outlineView;
|
||||||
- (NSArray *)resources; // return the array as non-mutable
|
- (NSArray *)resources; // return the array as non-mutable
|
||||||
|
|
||||||
- (NSString *)creator;
|
- (NSData *)creator;
|
||||||
- (NSString *)type;
|
- (NSData *)type;
|
||||||
- (IBAction)creatorChanged:(id)sender;
|
- (IBAction)creatorChanged:(id)sender;
|
||||||
- (IBAction)typeChanged:(id)sender;
|
- (IBAction)typeChanged:(id)sender;
|
||||||
- (void)setCreator:(NSString *)oldCreator;
|
- (BOOL)setCreator:(NSData *)newCreator;
|
||||||
- (void)setType:(NSString *)oldType;
|
- (BOOL)setType:(NSData *)newType;
|
||||||
- (void)setCreator:(NSString *)newCreator andType:(NSString *)newType;
|
- (BOOL)setCreator:(NSData *)newCreator andType:(NSData *)newType;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if( self )
|
if(!self) return nil;
|
||||||
{
|
[self setWraps:NO];
|
||||||
drawImage = YES;
|
drawImage = YES;
|
||||||
}
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +106,6 @@
|
|||||||
|
|
||||||
// get image frame
|
// get image frame
|
||||||
NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
|
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] */)
|
if([self drawsBackground] && ![self isHighlighted] /* ![self cellAttribute:NSCellHighlighted] */)
|
||||||
{
|
{
|
||||||
[[self backgroundColor] set];
|
[[self backgroundColor] set];
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
float value = [obj floatValue];
|
float value = [obj floatValue];
|
||||||
int power = 0;
|
int power = 0;
|
||||||
|
|
||||||
while( value >= 1024 && power <= 30 )
|
while( value >= 1024 /*&& power <= 30*/ )
|
||||||
{
|
{
|
||||||
power += 10; // 10 == KB, 20 == MB, 30+ == GB
|
power += 10; // 10 == KB, 20 == MB, 30+ == GB
|
||||||
value /= 1024;
|
value /= 1024;
|
||||||
|
12
Cocoa/English.lproj/AboutPanel.nib/info.nib
generated
@ -1,20 +1,20 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="0.9">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>IBDocumentLocation</key>
|
<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>
|
<key>IBFramework Version</key>
|
||||||
<string>248.0</string>
|
<string>446.1</string>
|
||||||
<key>IBLockedObjects</key>
|
<key>IBLockedObjects</key>
|
||||||
<array>
|
<array>
|
||||||
<integer>25</integer>
|
<integer>25</integer>
|
||||||
</array>
|
</array>
|
||||||
<key>IBOpenObjects</key>
|
<key>IBOpenObjects</key>
|
||||||
<array>
|
<array>
|
||||||
<integer>23</integer>
|
<integer>21</integer>
|
||||||
</array>
|
</array>
|
||||||
<key>IBSystem Version</key>
|
<key>IBSystem Version</key>
|
||||||
<string>5P48</string>
|
<string>8L127</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
BIN
Cocoa/English.lproj/AboutPanel.nib/objects.nib
generated
30
Cocoa/English.lproj/Application.nib/classes.nib
generated
@ -1,10 +1,18 @@
|
|||||||
{
|
{
|
||||||
IBClasses = (
|
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;
|
CLASS = ApplicationDelegate;
|
||||||
LANGUAGE = ObjC;
|
LANGUAGE = ObjC;
|
||||||
OUTLETS = {forkTableView = NSTableView; openAuxView = NSView; };
|
OUTLETS = {openPanelDelegate = OpenPanelDelegate; };
|
||||||
SUPERCLASS = NSObject;
|
SUPERCLASS = NSObject;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -15,12 +23,12 @@
|
|||||||
findNext = id;
|
findNext = id;
|
||||||
findPrevious = id;
|
findPrevious = id;
|
||||||
findWithSelection = id;
|
findWithSelection = id;
|
||||||
myAction = id;
|
|
||||||
openResources = id;
|
openResources = id;
|
||||||
openResourcesAsHex = id;
|
openResourcesAsHex = id;
|
||||||
openResourcesInTemplate = id;
|
openResourcesInTemplate = id;
|
||||||
playSound = id;
|
playSound = id;
|
||||||
revertResourceToSaved = id;
|
revertResource = id;
|
||||||
|
saveResource = id;
|
||||||
scrollToSelection = id;
|
scrollToSelection = id;
|
||||||
showAbout = id;
|
showAbout = id;
|
||||||
showCreateResourceSheet = id;
|
showCreateResourceSheet = id;
|
||||||
@ -29,17 +37,27 @@
|
|||||||
showInfo = id;
|
showInfo = id;
|
||||||
showPrefs = id;
|
showPrefs = id;
|
||||||
showSelectTemplateSheet = id;
|
showSelectTemplateSheet = id;
|
||||||
|
useIconView = id;
|
||||||
|
useListView = id;
|
||||||
};
|
};
|
||||||
CLASS = FirstResponder;
|
CLASS = FirstResponder;
|
||||||
LANGUAGE = ObjC;
|
LANGUAGE = ObjC;
|
||||||
SUPERCLASS = NSObject;
|
SUPERCLASS = NSObject;
|
||||||
},
|
},
|
||||||
|
{CLASS = NSOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; },
|
||||||
{
|
{
|
||||||
CLASS = OpenFileDataSource;
|
ACTIONS = {addFork = id; removeFork = id; };
|
||||||
|
CLASS = OpenPanelDelegate;
|
||||||
LANGUAGE = ObjC;
|
LANGUAGE = ObjC;
|
||||||
OUTLETS = {forkTableView = NSTableView; };
|
OUTLETS = {
|
||||||
|
addForkButton = NSButton;
|
||||||
|
forkTableView = NSTableView;
|
||||||
|
openPanelAccessoryView = NSView;
|
||||||
|
removeForkButton = NSButton;
|
||||||
|
};
|
||||||
SUPERCLASS = NSObject;
|
SUPERCLASS = NSObject;
|
||||||
},
|
},
|
||||||
|
{CLASS = OutlineSortView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; },
|
||||||
{
|
{
|
||||||
ACTIONS = {
|
ACTIONS = {
|
||||||
clear = id;
|
clear = id;
|
||||||
|
15
Cocoa/English.lproj/Application.nib/info.nib
generated
@ -3,22 +3,25 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>IBDocumentLocation</key>
|
<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>
|
<key>IBEditorPositions</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>246</key>
|
<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>
|
<key>29</key>
|
||||||
<string>22 682 347 44 0 0 1024 746 </string>
|
<string>66 658 366 44 0 0 1600 1002 </string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>IBFramework Version</key>
|
<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>
|
<key>IBOpenObjects</key>
|
||||||
<array>
|
<array>
|
||||||
<integer>246</integer>
|
|
||||||
<integer>29</integer>
|
<integer>29</integer>
|
||||||
</array>
|
</array>
|
||||||
<key>IBSystem Version</key>
|
<key>IBSystem Version</key>
|
||||||
<string>7A202</string>
|
<string>8L127</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</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>
|
<string>58 46 387 357 0 0 832 602 </string>
|
||||||
<key>IBFramework Version</key>
|
<key>IBFramework Version</key>
|
||||||
<string>326.0</string>
|
<string>326.0</string>
|
||||||
|
<key>IBOldestOS</key>
|
||||||
|
<integer>3</integer>
|
||||||
|
<key>IBOpenObjects</key>
|
||||||
|
<array>
|
||||||
|
<integer>20</integer>
|
||||||
|
</array>
|
||||||
<key>IBSystem Version</key>
|
<key>IBSystem Version</key>
|
||||||
<string>7A202</string>
|
<string>7A179</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</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;
|
SUPERCLASS = NSObject;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ACTIONS = {attributesChanged = id; nameChanged = id; };
|
ACTIONS = {attributesChanged = id; };
|
||||||
CLASS = InfoWindowController;
|
CLASS = InfoWindowController;
|
||||||
LANGUAGE = ObjC;
|
LANGUAGE = ObjC;
|
||||||
OUTLETS = {
|
OUTLETS = {
|
||||||
@ -21,7 +21,6 @@
|
|||||||
};
|
};
|
||||||
SUPERCLASS = NSWindowController;
|
SUPERCLASS = NSWindowController;
|
||||||
},
|
},
|
||||||
{CLASS = NSWindowController; LANGUAGE = ObjC; SUPERCLASS = NSResponder; },
|
|
||||||
{CLASS = SizeFormatter; LANGUAGE = ObjC; SUPERCLASS = NSNumberFormatter; }
|
{CLASS = SizeFormatter; LANGUAGE = ObjC; SUPERCLASS = NSNumberFormatter; }
|
||||||
);
|
);
|
||||||
IBVersion = 1;
|
IBVersion = 1;
|
||||||
|
14
Cocoa/English.lproj/InfoWindow.nib/info.nib
generated
@ -3,16 +3,12 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>IBDocumentLocation</key>
|
<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>
|
<key>IBFramework Version</key>
|
||||||
<string>326.0</string>
|
<string>439.0</string>
|
||||||
<key>IBOpenObjects</key>
|
<key>IBOldestOS</key>
|
||||||
<array>
|
<integer>0</integer>
|
||||||
<integer>35</integer>
|
|
||||||
<integer>5</integer>
|
|
||||||
<integer>50</integer>
|
|
||||||
</array>
|
|
||||||
<key>IBSystem Version</key>
|
<key>IBSystem Version</key>
|
||||||
<string>7A202</string>
|
<string>8I127</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</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 = (
|
IBClasses = (
|
||||||
{CLASS = AttributesFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; },
|
{CLASS = AttributesFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; },
|
||||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||||
{
|
|
||||||
CLASS = NameFormatter;
|
|
||||||
LANGUAGE = ObjC;
|
|
||||||
OUTLETS = {outlineView = NSOutlineView; };
|
|
||||||
SUPERCLASS = NSFormatter;
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
CLASS = OutlineViewDelegate;
|
CLASS = OutlineViewDelegate;
|
||||||
LANGUAGE = ObjC;
|
LANGUAGE = ObjC;
|
||||||
OUTLETS = {
|
OUTLETS = {
|
||||||
attributesFormatter = NSFormatter;
|
attributesFormatter = NSFormatter;
|
||||||
nameFormatter = NSFormatter;
|
|
||||||
sizeFormatter = NSNumberFormatter;
|
sizeFormatter = NSNumberFormatter;
|
||||||
window = NSWindow;
|
window = NSWindow;
|
||||||
};
|
};
|
||||||
SUPERCLASS = NSObject;
|
SUPERCLASS = NSObject;
|
||||||
},
|
},
|
||||||
|
{CLASS = RKOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; },
|
||||||
{
|
{
|
||||||
CLASS = ResourceDataSource;
|
CLASS = ResourceDataSource;
|
||||||
LANGUAGE = ObjC;
|
LANGUAGE = ObjC;
|
||||||
|
10
Cocoa/English.lproj/ResourceDocument.nib/info.nib
generated
@ -3,11 +3,15 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>IBDocumentLocation</key>
|
<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>
|
<key>IBFramework Version</key>
|
||||||
<string>286.0</string>
|
<string>349.0</string>
|
||||||
|
<key>IBLockedObjects</key>
|
||||||
|
<array>
|
||||||
|
<integer>146</integer>
|
||||||
|
</array>
|
||||||
<key>IBSystem Version</key>
|
<key>IBSystem Version</key>
|
||||||
<string>6F21</string>
|
<string>7H63</string>
|
||||||
<key>IBUserGuides</key>
|
<key>IBUserGuides</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CreateResourceSheet</key>
|
<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 = (
|
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;
|
CLASS = HexEditorDelegate;
|
||||||
LANGUAGE = ObjC;
|
LANGUAGE = ObjC;
|
||||||
@ -13,18 +26,20 @@
|
|||||||
};
|
};
|
||||||
SUPERCLASS = NSObject;
|
SUPERCLASS = NSObject;
|
||||||
},
|
},
|
||||||
|
{CLASS = HexEditorTextView; LANGUAGE = ObjC; SUPERCLASS = NSTextView; },
|
||||||
|
{CLASS = HexTextView; LANGUAGE = ObjC; SUPERCLASS = HexEditorTextView; },
|
||||||
{
|
{
|
||||||
ACTIONS = {showFind = id; };
|
ACTIONS = {showFind = id; };
|
||||||
CLASS = HexWindowController;
|
CLASS = HexWindowController;
|
||||||
LANGUAGE = ObjC;
|
LANGUAGE = ObjC;
|
||||||
OUTLETS = {
|
OUTLETS = {
|
||||||
ascii = NSTextView;
|
ascii = NSTextView;
|
||||||
asciiScroll = NSScrollView;
|
copySubmenu = NSMenu;
|
||||||
hex = NSTextView;
|
hex = NSTextView;
|
||||||
hexDelegate = HexEditorDelegate;
|
hexDelegate = HexEditorDelegate;
|
||||||
hexScroll = NSScrollView;
|
|
||||||
message = NSTextField;
|
message = NSTextField;
|
||||||
offset = NSTextView;
|
offset = NSTextView;
|
||||||
|
pasteSubmenu = NSMenu;
|
||||||
};
|
};
|
||||||
SUPERCLASS = NSWindowController;
|
SUPERCLASS = NSWindowController;
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,34 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>IBDocumentLocation</key>
|
<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>
|
<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>
|
<key>IBOpenObjects</key>
|
||||||
<array>
|
<array>
|
||||||
<integer>6</integer>
|
<integer>24</integer>
|
||||||
|
<integer>36</integer>
|
||||||
</array>
|
</array>
|
||||||
<key>IBSystem Version</key>
|
<key>IBSystem Version</key>
|
||||||
<string>6F21</string>
|
<string>8L127</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
BIN
Cocoa/Plug-Ins/Hex Editor/English.lproj/HexWindow.nib/keyedobjects.nib
generated
Normal file
@ -29,7 +29,7 @@
|
|||||||
// enable/disable boxes
|
// enable/disable boxes
|
||||||
[searchSelectionOnlyBox setEnabled:([(NSTextView *)[[sender window] firstResponder] rangeForUserTextChange].length != 0)];
|
[searchSelectionOnlyBox setEnabled:([(NSTextView *)[[sender window] firstResponder] rangeForUserTextChange].length != 0)];
|
||||||
|
|
||||||
// set inital vales
|
// set inital values
|
||||||
if( ![searchSelectionOnlyBox isEnabled] ) [searchSelectionOnlyBox setIntValue:0];
|
if( ![searchSelectionOnlyBox isEnabled] ) [searchSelectionOnlyBox setIntValue:0];
|
||||||
|
|
||||||
// show sheet
|
// show sheet
|
||||||
|
@ -2,33 +2,34 @@
|
|||||||
|
|
||||||
#import "ResKnifeResourceProtocol.h"
|
#import "ResKnifeResourceProtocol.h"
|
||||||
|
|
||||||
@class HexWindowController;
|
@class HexWindowController, HexTextView, AsciiTextView;
|
||||||
|
|
||||||
@interface HexEditorDelegate : NSObject
|
@interface HexEditorDelegate : NSObject
|
||||||
{
|
{
|
||||||
IBOutlet HexWindowController *controller;
|
IBOutlet HexWindowController *controller;
|
||||||
IBOutlet NSTextView *ascii;
|
|
||||||
IBOutlet NSTextView *hex;
|
|
||||||
IBOutlet NSTextView *offset;
|
IBOutlet NSTextView *offset;
|
||||||
|
IBOutlet HexTextView *hex;
|
||||||
|
IBOutlet AsciiTextView *ascii;
|
||||||
IBOutlet NSTextField *message;
|
IBOutlet NSTextField *message;
|
||||||
|
|
||||||
BOOL editedLow;
|
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 *)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 *)hex;
|
||||||
- (NSTextView *)ascii;
|
- (NSTextView *)ascii;
|
||||||
|
|
||||||
- (BOOL)editedLow;
|
- (BOOL)editedLow;
|
||||||
- (void)setEditedLow:(BOOL)flag;
|
- (void)setEditedLow:(BOOL)flag;
|
||||||
|
- (NSRange)rangeForUserTextChange;
|
||||||
|
|
||||||
@end
|
@end
|
@ -1,7 +1,6 @@
|
|||||||
#import "HexEditorDelegate.h"
|
#import "HexEditorDelegate.h"
|
||||||
#import "HexWindowController.h"
|
#import "HexWindowController.h"
|
||||||
|
#import "HexTextView.h"
|
||||||
/* Ideas, method names, and occasionally code stolen from HexEditor by Raphael Sebbe http://raphaelsebbe.multimania.com/ */
|
|
||||||
|
|
||||||
@implementation HexEditorDelegate
|
@implementation HexEditorDelegate
|
||||||
|
|
||||||
@ -14,9 +13,31 @@
|
|||||||
return self;
|
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 */
|
/* data re-representation methods */
|
||||||
|
|
||||||
- (NSString *)offsetRepresentation:(NSData *)data;
|
- (NSString *)offsetRepresentation:(NSData *)data
|
||||||
{
|
{
|
||||||
int dataLength = [data length], bytesPerRow = [controller bytesPerRow];
|
int dataLength = [data length], bytesPerRow = [controller bytesPerRow];
|
||||||
int rows = (dataLength / bytesPerRow) + ((dataLength % bytesPerRow)? 1:0);
|
int rows = (dataLength / bytesPerRow) + ((dataLength % bytesPerRow)? 1:0);
|
||||||
@ -29,122 +50,30 @@
|
|||||||
return representation;
|
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 */
|
/* 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)textView:(NSTextView *)textView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange
|
||||||
{
|
{
|
||||||
NSRange hexRange, asciiRange, byteRange = NSMakeRange(0,0);
|
NSRange hexRange, asciiRange, byteRange = NSMakeRange(0,0);
|
||||||
@ -156,16 +85,14 @@
|
|||||||
|
|
||||||
if( textView == hex ) // we're selecting hexadecimal
|
if( textView == hex ) // we're selecting hexadecimal
|
||||||
{
|
{
|
||||||
byteRange = [self byteRangeFromHexRange:newSelectedCharRange];
|
byteRange = [HexWindowController byteRangeFromHexRange:newSelectedCharRange];
|
||||||
asciiRange = [self asciiRangeFromByteRange:byteRange];
|
asciiRange = [HexWindowController asciiRangeFromByteRange:byteRange];
|
||||||
[ascii setSelectedRange:asciiRange];
|
[ascii setSelectedRange:asciiRange];
|
||||||
}
|
}
|
||||||
else if( textView == ascii ) // we're selecting ASCII
|
else if( textView == ascii ) // we're selecting ASCII
|
||||||
{
|
{
|
||||||
byteRange = [self byteRangeFromAsciiRange:newSelectedCharRange];
|
byteRange = [HexWindowController byteRangeFromAsciiRange:newSelectedCharRange];
|
||||||
hexRange = [self hexRangeFromByteRange:byteRange];
|
hexRange = [HexWindowController hexRangeFromByteRange:byteRange];
|
||||||
if( hexRange.length > 0 )
|
|
||||||
hexRange.length -= 1;
|
|
||||||
[hex setSelectedRange:hexRange];
|
[hex setSelectedRange:hexRange];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,36 +105,9 @@
|
|||||||
return newSelectedCharRange;
|
return newSelectedCharRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* range conversion methods */
|
- (HexWindowController *)controller
|
||||||
|
|
||||||
- (NSRange)byteRangeFromHexRange:(NSRange)hexRange;
|
|
||||||
{
|
{
|
||||||
// valid for all window widths
|
return controller;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSTextView *)hex
|
- (NSTextView *)hex
|
||||||
@ -230,4 +130,17 @@
|
|||||||
editedLow = flag;
|
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
|
@end
|
@ -2,16 +2,18 @@
|
|||||||
#import "HexEditorDelegate.h"
|
#import "HexEditorDelegate.h"
|
||||||
#import "HexWindowController.h"
|
#import "HexWindowController.h"
|
||||||
|
|
||||||
@interface HexTextView : NSTextView
|
@interface HexEditorTextView : NSTextView
|
||||||
{
|
- (IBAction)copyASCII:(id)sender;
|
||||||
}
|
- (IBAction)copyHex:(id)sender;
|
||||||
- (IBAction)clear:(id)sender;
|
|
||||||
- (IBAction)pasteAsASCII:(id)sender;
|
- (IBAction)pasteAsASCII:(id)sender;
|
||||||
- (IBAction)pasteAsHex:(id)sender;
|
- (IBAction)pasteAsHex:(id)sender;
|
||||||
- (IBAction)pasteAsUnicode:(id)sender;
|
- (IBAction)pasteAsUnicode:(id)sender;
|
||||||
|
- (IBAction)clear:(id)sender;
|
||||||
- (void)editData:(NSData *)data replaceBytesInRange:(NSRange)range withData:(NSData *)newData;
|
- (void)editData:(NSData *)data replaceBytesInRange:(NSRange)range withData:(NSData *)newData;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface NSTextView (HexTextView)
|
@interface HexTextView : HexEditorTextView
|
||||||
- (void)swapForHexTextView;
|
@end
|
||||||
|
|
||||||
|
@interface AsciiTextView : HexEditorTextView
|
||||||
@end
|
@end
|
@ -1,88 +1,10 @@
|
|||||||
#import "HexTextView.h"
|
#import "HexTextView.h"
|
||||||
|
#import "NSData-HexRepresentation.h"
|
||||||
|
|
||||||
@implementation HexTextView
|
@implementation HexEditorTextView
|
||||||
|
|
||||||
- (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];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NSText overrides */
|
/* 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
|
- (IBAction)cut:(id)sender
|
||||||
{
|
{
|
||||||
[self copy:sender];
|
[self copy:sender];
|
||||||
@ -91,110 +13,84 @@
|
|||||||
|
|
||||||
- (IBAction)copy:(id)sender
|
- (IBAction)copy:(id)sender
|
||||||
{
|
{
|
||||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||||
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
||||||
|
|
||||||
// get selection range
|
[pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
|
||||||
if( self == (id) [[self delegate] hex] )
|
[pb setData:[[(HexWindowController *)[[self window] windowController] data] subdataWithRange:selection] forType:NSStringPboardType];
|
||||||
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];
|
- (IBAction)copyASCII:(id)sender
|
||||||
[pb setData:[[[[self window] windowController] data] subdataWithRange:byteSelection] forType:NSStringPboardType];
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)copyHex:(id)sender
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)paste:(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.
|
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||||
// what about unicode? should I paste "00 63 00 64" as "63 64" ("Paste As ASCII" submenu item)?
|
|
||||||
|
|
||||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
|
||||||
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
||||||
|
|
||||||
// get selection range
|
// pastes data as it is on the clipboard
|
||||||
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]])
|
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
|
- (IBAction)pasteAsASCII:(id)sender
|
||||||
{
|
{
|
||||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||||
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
||||||
|
|
||||||
// get selection range
|
// converts whatever string encoding is on the clipboard to the default C string encoding, then pastes
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if([pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]])
|
if([pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]])
|
||||||
{
|
{
|
||||||
NSString *hexString = [[self delegate] hexRepresentation:[pb dataForType:NSStringPboardType]];
|
NSData *asciiData = [[pb stringForType:NSStringPboardType] dataUsingEncoding:[NSString defaultCStringEncoding] allowLossyConversion:YES];
|
||||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:[NSData dataWithBytes:[hexString cString] length:[hexString cStringLength]]];
|
[self editData:[[[self window] windowController] data] replaceBytesInRange:selection withData:asciiData];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)pasteAsUnicode:(id)sender
|
- (IBAction)pasteAsUnicode:(id)sender
|
||||||
{
|
{
|
||||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||||
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
|
||||||
|
|
||||||
// get selection range
|
// converts whatever string encoding is on the clipboard to Unicode, strips off the byte order mark, then pastes
|
||||||
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]])
|
if([pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]])
|
||||||
{
|
{
|
||||||
NSData *unicodeData = [[NSString stringWithUTF8String:[[pb dataForType:NSStringPboardType] bytes]] dataUsingEncoding:NSUnicodeStringEncoding];
|
NSMutableData *unicodeData = [[[pb stringForType:NSStringPboardType] dataUsingEncoding:NSUnicodeStringEncoding] mutableCopy];
|
||||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:byteSelection withData:unicodeData];
|
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 */
|
/* 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
|
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
|
||||||
{
|
{
|
||||||
|
return NSDragOperationNone;
|
||||||
/* if(isLocal) return NSDragOperationEvery;
|
/* if(isLocal) return NSDragOperationEvery;
|
||||||
else return NSDragOperationCopy;
|
else return NSDragOperationCopy;
|
||||||
*/ return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric;
|
return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric;
|
||||||
}
|
*/}
|
||||||
|
|
||||||
static NSRange draggedRange;
|
static NSRange draggedRange;
|
||||||
|
|
||||||
@ -236,7 +125,7 @@ static NSRange draggedRange;
|
|||||||
|
|
||||||
- (void)draggedImage:(NSImage *)image endedAt:(NSPoint)point operation:(NSDragOperation)operation
|
- (void)draggedImage:(NSImage *)image endedAt:(NSPoint)point operation:(NSDragOperation)operation
|
||||||
{
|
{
|
||||||
/* if( operation == NSDragOperationMove )
|
if(operation == NSDragOperationMove)
|
||||||
{
|
{
|
||||||
NSRange selection = [self rangeForUserTextChange];
|
NSRange selection = [self rangeForUserTextChange];
|
||||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:draggedRange withData:[NSData data]];
|
[self editData:[[[self window] windowController] data] replaceBytesInRange:draggedRange withData:[NSData data]];
|
||||||
@ -247,7 +136,7 @@ static NSRange draggedRange;
|
|||||||
if(selection.location > draggedRange.location)
|
if(selection.location > draggedRange.location)
|
||||||
selection.location -= draggedRange.length;
|
selection.location -= draggedRange.length;
|
||||||
[self setSelectedRange:selection];
|
[self setSelectedRange:selection];
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
|
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
|
||||||
@ -263,18 +152,18 @@ static NSRange draggedRange;
|
|||||||
// get the insertion point location
|
// get the insertion point location
|
||||||
NSPasteboard *pb = [sender draggingPasteboard];
|
NSPasteboard *pb = [sender draggingPasteboard];
|
||||||
NSData *pastedData = [pb dataForType:NSStringPboardType];
|
NSData *pastedData = [pb dataForType:NSStringPboardType];
|
||||||
int charIndex = [self _insertionGlyphIndexForDrag:sender];
|
unsigned int charIndex = (unsigned int) [self _insertionGlyphIndexForDrag:sender];
|
||||||
NSRange selection;
|
NSRange selection;
|
||||||
|
|
||||||
// convert hex string to data
|
// convert hex string to data
|
||||||
if([sender draggingSource] == [[self delegate] hex])
|
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([sender draggingSource] == [[self delegate] hex] || [sender draggingSource] == [[self delegate] ascii])
|
||||||
// if(operation == NSDragOperationMove)
|
// if(operation == NSDragOperationMove)
|
||||||
{
|
{
|
||||||
NSRange deleteRange = draggedRange;
|
NSRange deleteRange = draggedRange;
|
||||||
if( self == [[self delegate] hex] )
|
if(self == (id) [[self delegate] hex])
|
||||||
{
|
{
|
||||||
deleteRange.location /= 3;
|
deleteRange.location /= 3;
|
||||||
deleteRange.length += 1;
|
deleteRange.length += 1;
|
||||||
@ -290,7 +179,7 @@ static NSRange draggedRange;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// insert data at insertion point
|
// 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];
|
[self editData:[[[self window] windowController] data] replaceBytesInRange:NSMakeRange(charIndex,0) withData:pastedData];
|
||||||
|
|
||||||
// set the new selection/insertion point
|
// set the new selection/insertion point
|
||||||
@ -311,21 +200,10 @@ static NSRange draggedRange;
|
|||||||
|
|
||||||
- (void)insertText:(NSString *)string
|
- (void)insertText:(NSString *)string
|
||||||
{
|
{
|
||||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||||
NSMutableData *data = [[[[self window] windowController] data] mutableCopy];
|
NSMutableData *data = [[[[self window] windowController] data] mutableCopy];
|
||||||
NSData *replaceData = [NSData dataWithBytes:[string cString] length:[string cStringLength]];
|
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])
|
if(self == (id) [[self delegate] hex])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -338,12 +216,19 @@ static NSRange draggedRange;
|
|||||||
else if(typedChar >= 0x61 && typedChar <= 0x66) typedChar -= 0x57; // a to f
|
else if(typedChar >= 0x61 && typedChar <= 0x66) typedChar -= 0x57; // a to f
|
||||||
else return;
|
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
|
// select & retrieve old byte so it gets replaced
|
||||||
char prevByte;
|
char prevByte;
|
||||||
byteSelection = NSMakeRange(byteSelection.location -1, 1);
|
selection = NSMakeRange(selection.location -1, 1);
|
||||||
[data getBytes:&prevByte range:byteSelection];
|
[data getBytes:&prevByte range:selection];
|
||||||
|
|
||||||
// shift typed char into high bits and add new low char
|
// shift typed char into high bits and add new low char
|
||||||
prevByte <<= 4; // store high bit
|
prevByte <<= 4; // store high bit
|
||||||
@ -351,89 +236,61 @@ static NSRange draggedRange;
|
|||||||
replaceData = [NSData dataWithBytes:&prevByte length:1];
|
replaceData = [NSData dataWithBytes:&prevByte length:1];
|
||||||
[[self delegate] setEditedLow:NO];
|
[[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)
|
// replace bytes (updates views implicitly, records an undo)
|
||||||
[self editData:data replaceBytesInRange:byteSelection withData:replaceData];
|
[self editData:data replaceBytesInRange:selection withData:replaceData];
|
||||||
[data release];
|
[data release];
|
||||||
|
|
||||||
// set the new selection/insertion point
|
// set the new selection (insertion point)
|
||||||
byteSelection.location++;
|
selection.location++;
|
||||||
byteSelection.length = 0;
|
selection.length = 0;
|
||||||
if( self == (id) [[self delegate] hex] )
|
if(self == (id) [[self delegate] hex]) selection = [HexWindowController hexRangeFromByteRange:selection];
|
||||||
selection = [[self delegate] hexRangeFromByteRange:byteSelection];
|
if(self == (id) [[self delegate] ascii]) selection = [HexWindowController asciiRangeFromByteRange:selection];
|
||||||
else if( self == (id) [[self delegate] ascii] )
|
|
||||||
selection = [[self delegate] asciiRangeFromByteRange:byteSelection];
|
|
||||||
[self setSelectedRange:selection];
|
[self setSelectedRange:selection];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)deleteBackward:(id)sender
|
- (IBAction)deleteBackward:(id)sender
|
||||||
{
|
{
|
||||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||||
NSMutableData *data = [[[[self window] windowController] data] mutableCopy];
|
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
|
// adjust selection if is insertion point
|
||||||
if( byteSelection.length == 0 && selection.location > 0 )
|
if(selection.length == 0 && selection.location > 0)
|
||||||
{
|
{
|
||||||
byteSelection.location -= 1;
|
selection.location -= 1;
|
||||||
byteSelection.length = 1;
|
selection.length = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace bytes (updates views implicitly)
|
// replace bytes (updates views implicitly)
|
||||||
[self editData:data replaceBytesInRange:byteSelection withData:[NSData data]];
|
[self editData:data replaceBytesInRange:selection withData:[NSData data]];
|
||||||
[data release];
|
[data release];
|
||||||
|
|
||||||
// set the new selection/insertion point
|
// set the new selection (insertion point)
|
||||||
if( selection.length == 0 )
|
if(selection.length == 0 && selection.location > 0)
|
||||||
selection.location -= 1;
|
selection.location -= 1;
|
||||||
else selection.length = 0;
|
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];
|
[self setSelectedRange:selection];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)deleteForward:(id)sender
|
- (IBAction)deleteForward:(id)sender
|
||||||
{
|
{
|
||||||
NSRange selection = [self rangeForUserTextChange], byteSelection;
|
NSRange selection = [(HexEditorDelegate *)[self delegate] rangeForUserTextChange];
|
||||||
NSMutableData *data = [[[[self window] windowController] data] mutableCopy];
|
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
|
// adjust selection if is insertion point
|
||||||
if( byteSelection.length == 0 && selection.location < [[self string] length] -1 )
|
if(selection.length == 0 && [self rangeForUserTextChange].location < [[self string] length] -1)
|
||||||
byteSelection.length = 1;
|
selection.length = 1;
|
||||||
|
|
||||||
// replace bytes (updates views implicitly)
|
// replace bytes (updates views implicitly)
|
||||||
[self editData:data replaceBytesInRange:byteSelection withData:[NSData data]];
|
[self editData:data replaceBytesInRange:selection withData:[NSData data]];
|
||||||
[data release];
|
[data release];
|
||||||
|
|
||||||
// set the new selection/insertion point
|
// set the new selection/insertion point
|
||||||
|
selection = [self rangeForUserTextChange];
|
||||||
selection.length = 0;
|
selection.length = 0;
|
||||||
[self setSelectedRange:selection];
|
[self setSelectedRange:selection];
|
||||||
}
|
}
|
||||||
@ -458,6 +315,11 @@ static NSRange draggedRange;
|
|||||||
[self transpose:sender];
|
[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
|
- (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
|
// 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;
|
BOOL closeUndoGroup = NO;
|
||||||
id undoStack = nil; // object of class _NSUndoStack
|
id undoStack = nil; // object of class _NSUndoStack
|
||||||
if(![[[self window] undoManager] isUndoing])
|
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)
|
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]];
|
[newData replaceBytesInRange:range withBytes:[newBytes bytes] length:[newBytes length]];
|
||||||
[[(HexWindowController *)[[self window] windowController] resource] setData:newData];
|
[[(HexWindowController *)[[self window] windowController] resource] setData:newData];
|
||||||
[self setSelectedRange:NSMakeRange(range.location + [newBytes length], 0)];
|
[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
|
// record undo with new data object
|
||||||
[[[[self window] undoManager] prepareWithInvocationTarget:self] editData:newData replaceBytesInRange:newRange withData:oldBytes];
|
[[[[self window] undoManager] prepareWithInvocationTarget:self] editData:newData replaceBytesInRange:newRange withData:oldBytes];
|
||||||
[[[self window] undoManager] setActionName:NSLocalizedString(@"Typing", nil)];
|
[[[self window] undoManager] setActionName:NSLocalizedString(@"Typing", nil)];
|
||||||
if(closeUndoGroup)
|
if(closeUndoGroup)
|
||||||
[[[self window] undoManager] endUndoGrouping];
|
[[[self window] undoManager] endUndoGrouping];
|
||||||
// NSLog( @"%@", undoStack );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@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
|
@end
|
||||||
|
|
||||||
|
@implementation AsciiTextView
|
||||||
|
|
||||||
|
@end
|
||||||
|
@ -8,22 +8,31 @@
|
|||||||
#define kWindowStepWidthPerChar 28
|
#define kWindowStepWidthPerChar 28
|
||||||
#define kWindowStepCharsPerStep 1
|
#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>
|
@interface HexWindowController : NSWindowController <ResKnifePluginProtocol>
|
||||||
{
|
{
|
||||||
IBOutlet HexEditorDelegate *hexDelegate;
|
IBOutlet HexEditorDelegate *hexDelegate;
|
||||||
IBOutlet NSScrollView *asciiScroll;
|
IBOutlet NSTextView *offset; // these four should be phased out whenever possible
|
||||||
IBOutlet NSScrollView *hexScroll;
|
IBOutlet HexTextView *hex; // these four should be phased out whenever possible
|
||||||
IBOutlet NSTextView *ascii;
|
IBOutlet AsciiTextView *ascii; // these four should be phased out whenever possible
|
||||||
IBOutlet NSTextView *hex;
|
IBOutlet NSTextField *message; // these four should be phased out whenever possible
|
||||||
IBOutlet NSTextView *offset;
|
IBOutlet NSMenu *copySubmenu;
|
||||||
IBOutlet NSTextField *message;
|
|
||||||
IBOutlet NSMenu *pasteSubmenu;
|
IBOutlet NSMenu *pasteSubmenu;
|
||||||
|
|
||||||
NSUndoManager *undoManager;
|
|
||||||
id <ResKnifeResourceProtocol> resource;
|
id <ResKnifeResourceProtocol> resource;
|
||||||
id <ResKnifeResourceProtocol> backup;
|
id <ResKnifeResourceProtocol> backup;
|
||||||
|
|
||||||
BOOL liveEdit;
|
BOOL liveEdit;
|
||||||
int bytesPerRow;
|
int bytesPerRow;
|
||||||
|
NSUndoManager *undoManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
// conform to the ResKnifePluginProtocol with the inclusion of these methods
|
// conform to the ResKnifePluginProtocol with the inclusion of these methods
|
||||||
@ -34,11 +43,10 @@
|
|||||||
|
|
||||||
// save sheet methods
|
// save sheet methods
|
||||||
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
|
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
|
||||||
- (void)saveResource;
|
- (IBAction)saveResource:(id)sender;
|
||||||
- (void)revertResource;
|
- (IBAction)revertResource:(id)sender;
|
||||||
|
|
||||||
// normal methods
|
// normal methods
|
||||||
- (void)viewDidScroll:(NSNotification *)notification;
|
|
||||||
- (void)resourceNameDidChange:(NSNotification *)notification;
|
- (void)resourceNameDidChange:(NSNotification *)notification;
|
||||||
- (void)resourceDataDidChange:(NSNotification *)notification;
|
- (void)resourceDataDidChange:(NSNotification *)notification;
|
||||||
- (void)resourceWasSaved:(NSNotification *)notification;
|
- (void)resourceWasSaved:(NSNotification *)notification;
|
||||||
@ -48,5 +56,13 @@
|
|||||||
- (id)resource;
|
- (id)resource;
|
||||||
- (NSData *)data;
|
- (NSData *)data;
|
||||||
- (int)bytesPerRow;
|
- (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
|
@end
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#import "HexWindowController.h"
|
#import "HexWindowController.h"
|
||||||
#import "HexTextView.h"
|
#import "HexTextView.h"
|
||||||
#import "FindSheetController.h"
|
#import "FindSheetController.h"
|
||||||
|
#import "NSData-HexRepresentation.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
OSStatus Plug_InitInstance(Plug_PlugInRef plug, Plug_ResourceRef resource)
|
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
|
- (id)initWithResource:(id)newResource
|
||||||
{
|
{
|
||||||
self = [self initWithWindowNibName:@"HexWindow"];
|
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)
|
// 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];
|
undoManager = [[NSUndoManager alloc] init];
|
||||||
liveEdit = NO;
|
liveEdit = NO;
|
||||||
if(liveEdit)
|
if(liveEdit)
|
||||||
{
|
{
|
||||||
resource = [newResource retain];
|
resource = [newResource retain]; // resource to work on and monitor for external changes
|
||||||
backup = [newResource copy];
|
backup = [newResource copy]; // for reverting only
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resource = [newResource copy];
|
resource = [newResource copy]; // resource to work on
|
||||||
backup = [newResource retain];
|
backup = [newResource retain]; // actual resource to change when saving data and monitor for external changes
|
||||||
}
|
}
|
||||||
bytesPerRow = 16;
|
bytesPerRow = 16;
|
||||||
|
|
||||||
// load the window from the nib file and set it's title
|
// load the window from the nib file
|
||||||
[self window]; // implicitly loads nib
|
[self window];
|
||||||
[[self window] setTitle:[resource nameForEditorWindow]];
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
[(id)resource autorelease];
|
|
||||||
[undoManager release];
|
[undoManager release];
|
||||||
|
[(id)resource release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,68 +58,86 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
|||||||
{
|
{
|
||||||
[super windowDidLoad];
|
[super windowDidLoad];
|
||||||
|
|
||||||
// swap text views to instances of my class instead
|
{
|
||||||
[offset swapForHexTextView];
|
// set up tab, shift-tab and enter behaviour (cannot set these in IB at the moment)
|
||||||
[hex swapForHexTextView];
|
[hex setFieldEditor:YES];
|
||||||
[ascii swapForHexTextView];
|
[ascii setFieldEditor:YES];
|
||||||
|
|
||||||
// turn off the background for the offset column (IB is broken when it comes to this)
|
|
||||||
[offset setDrawsBackground:NO];
|
[offset setDrawsBackground:NO];
|
||||||
[[offset enclosingScrollView] setDrawsBackground:NO];
|
[[offset enclosingScrollView] setDrawsBackground:NO];
|
||||||
|
|
||||||
// set up tab, shift-tab and enter behaviour
|
// IB fonts get ignored for some reason
|
||||||
[hex setFieldEditor:YES];
|
NSFont *courier = [[NSFontManager sharedFontManager] fontWithFamily:@"Courier" traits:0 weight:5 size:12.0];
|
||||||
[ascii setFieldEditor:YES];
|
[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
|
// insert the resources' data into the text fields
|
||||||
[self refreshData:[resource data]];
|
[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
|
// 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(resourceNameDidChange:) name:ResourceNameDidChangeNotification object:resource];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceWasSavedNotification object:resource];
|
if(liveEdit) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceDataDidChangeNotification object:resource];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceWasSavedNotification object:backup];
|
else [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceDataDidChangeNotification object:backup];
|
||||||
|
|
||||||
// put other notifications here too, just for togetherness
|
// finally, set the window title & show the window
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[offset enclosingScrollView] contentView]];
|
[[self window] setTitle:[resource defaultWindowTitle]];
|
||||||
[[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
|
|
||||||
[self showWindow:self];
|
[self showWindow:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowDidResize:(NSNotification *)notification
|
- (void)windowDidResize:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
int width = [[notification object] frame].size.width;
|
float width = [[(NSWindow *)[notification object] contentView] frame].size.width;
|
||||||
int oldBytesPerRow = bytesPerRow;
|
int oldBytesPerRow = bytesPerRow;
|
||||||
bytesPerRow = (((width - (kWindowStepWidthPerChar * kWindowStepCharsPerStep) - 122) / (kWindowStepWidthPerChar * kWindowStepCharsPerStep)) + 1) * kWindowStepCharsPerStep;
|
bytesPerRow = (((width - (kWindowStepWidthPerChar * kWindowStepCharsPerStep) - 122) / (kWindowStepWidthPerChar * kWindowStepCharsPerStep)) + 1) * kWindowStepCharsPerStep;
|
||||||
if(bytesPerRow != oldBytesPerRow)
|
if(bytesPerRow != oldBytesPerRow)
|
||||||
[offset setString:[hexDelegate offsetRepresentation:[resource data]]];
|
[offset setString:[hexDelegate offsetRepresentation:[resource data]]];
|
||||||
[hexScroll setFrameSize:NSMakeSize( (bytesPerRow * 21) + 5, [hexScroll frame].size.height)];
|
[[hex enclosingScrollView] setFrameSize:NSMakeSize((bytesPerRow * 21) + 5, [[hex enclosingScrollView] frame].size.height)];
|
||||||
[asciiScroll setFrameOrigin:NSMakePoint( (bytesPerRow * 21) + 95, 20)];
|
[[ascii enclosingScrollView] setFrameOrigin:NSMakePoint((bytesPerRow * 21) + 95, 20)];
|
||||||
[asciiScroll setFrameSize:NSMakeSize( (bytesPerRow * 7) + 28, [asciiScroll frame].size.height)];
|
[[ascii enclosingScrollView] setFrameSize:NSMakeSize((bytesPerRow * 7) + 28, [[ascii enclosingScrollView] frame].size.height)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
// swap paste: menu item for my own paste submenu
|
|
||||||
NSMenu *editMenu = [[[NSApp mainMenu] itemAtIndex:2] 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:)]];
|
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 setEnabled:YES];
|
||||||
[pasteItem setKeyEquivalent:@"\0"]; // clear key equiv. (yes, really!)
|
[pasteItem setKeyEquivalent:@"\0"];
|
||||||
[pasteItem setKeyEquivalentModifierMask:0];
|
[pasteItem setKeyEquivalentModifierMask:0];
|
||||||
[editMenu setSubmenu:pasteSubmenu forItem:pasteItem];
|
[editMenu setSubmenu:pasteSubmenu forItem:pasteItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowDidResignKey:(NSNotification *)notification
|
- (void)windowDidResignKey:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
// swap my submenu for plain paste menu item
|
|
||||||
NSMenu *editMenu = [[[NSApp mainMenu] itemAtIndex:2] submenu];
|
NSMenu *editMenu = [[[NSApp mainMenu] itemAtIndex:2] submenu];
|
||||||
|
NSMenuItem *copyItem = [editMenu itemAtIndex:[editMenu indexOfItemWithSubmenu:copySubmenu]];
|
||||||
NSMenuItem *pasteItem = [editMenu itemAtIndex:[editMenu indexOfItemWithSubmenu:pasteSubmenu]];
|
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];
|
[editMenu setSubmenu:nil forItem:pasteItem];
|
||||||
[pasteItem setTarget:nil];
|
[pasteItem setTarget:nil];
|
||||||
[pasteItem setAction:@selector(paste:)];
|
[pasteItem setAction:@selector(paste:)];
|
||||||
@ -132,7 +149,7 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
|||||||
{
|
{
|
||||||
if([[self window] isDocumentEdited])
|
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;
|
return NO;
|
||||||
}
|
}
|
||||||
else return YES;
|
else return YES;
|
||||||
@ -142,13 +159,12 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
|||||||
{
|
{
|
||||||
switch(returnCode)
|
switch(returnCode)
|
||||||
{
|
{
|
||||||
case NSAlertDefaultReturn: // save
|
case NSAlertDefaultReturn: // keep
|
||||||
[self saveResource];
|
[self saveResource:nil];
|
||||||
[[self window] close];
|
[[self window] close];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NSAlertAlternateReturn: // don't save
|
case NSAlertAlternateReturn: // don't keep
|
||||||
[self revertResource];
|
|
||||||
[[self window] close];
|
[[self window] close];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -157,82 +173,32 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)saveResource
|
- (void)saveResource:(id)sender
|
||||||
{
|
{
|
||||||
if( liveEdit )
|
[backup setData:[[resource data] copy]];
|
||||||
{
|
|
||||||
[[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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (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
|
// bug: HexWindowController allocs a sheet controller, but it's never disposed of
|
||||||
FindSheetController *sheetController = [[FindSheetController alloc] initWithWindowNibName:@"FindSheet"];
|
FindSheetController *sheetController = [[FindSheetController alloc] initWithWindowNibName:@"FindSheet"];
|
||||||
[sheetController showFindSheet:self];
|
[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
|
- (void)resourceNameDidChange:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
[[self window] setTitle:[(id <ResKnifeResourceProtocol>)[notification object] nameForEditorWindow]];
|
[[self window] setTitle:[(id <ResKnifeResourceProtocol>)[notification object] defaultWindowTitle]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)resourceDataDidChange:(NSNotification *)notification
|
- (void)resourceDataDidChange:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
// ensure it's our resource which got changed (should always be true, we don't register for other resource notifications)
|
// 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)
|
if([notification object] == (id)resource)
|
||||||
{
|
{
|
||||||
[self refreshData:[resource data]];
|
[self refreshData:[resource data]];
|
||||||
@ -242,35 +208,21 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
|||||||
|
|
||||||
- (void)resourceWasSaved:(NSNotification *)notification
|
- (void)resourceWasSaved:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
NSLog( @"%@; %@; %@", [notification object], resource, backup );
|
id <ResKnifeResourceProtocol> object = [notification object];
|
||||||
if( [notification object] == (id)resource )
|
if(liveEdit)
|
||||||
{
|
{
|
||||||
// if resource gets saved, liveEdit is true and this resource is saving
|
// haven't worked out what to do here yet
|
||||||
[backup setData:[resource data]];
|
|
||||||
[self setDocumentEdited:NO];
|
|
||||||
}
|
}
|
||||||
else if( [notification object] == (id)backup && !liveEdit )
|
else
|
||||||
{
|
{
|
||||||
// backup will get saved by this resource if liveEdit is false, rather than the 'resource' variable
|
// this should refresh the view automatically
|
||||||
// but really the data to preserve is in the resource variable
|
[resource setData:[[object data] copy]];
|
||||||
[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]];
|
|
||||||
[self setDocumentEdited:NO];
|
[self setDocumentEdited:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)refreshData:(NSData *)data;
|
- (void)refreshData:(NSData *)data;
|
||||||
{
|
{
|
||||||
NSDictionary *dictionary;
|
|
||||||
NSMutableParagraphStyle *paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
|
||||||
|
|
||||||
// save selections
|
// save selections
|
||||||
NSRange hexSelection = [hex selectedRange];
|
NSRange hexSelection = [hex selectedRange];
|
||||||
NSRange asciiSelection = [ascii selectedRange];
|
NSRange asciiSelection = [ascii selectedRange];
|
||||||
@ -281,13 +233,16 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
|||||||
[ascii setDelegate:nil];
|
[ascii setDelegate:nil];
|
||||||
|
|
||||||
// prepare attributes dictionary
|
// prepare attributes dictionary
|
||||||
|
NSMutableParagraphStyle *paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||||
[paragraph setLineBreakMode:NSLineBreakByCharWrapping];
|
[paragraph setLineBreakMode:NSLineBreakByCharWrapping];
|
||||||
dictionary = [NSDictionary dictionaryWithObject:paragraph forKey:NSParagraphStyleAttributeName];
|
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:paragraph forKey:NSParagraphStyleAttributeName];
|
||||||
|
|
||||||
// do stuff with data
|
// do stuff with data
|
||||||
[offset setString:[hexDelegate offsetRepresentation:data]];
|
[offset setString:[hexDelegate offsetRepresentation:data]];
|
||||||
[hex setString:[hexDelegate hexRepresentation:data]];
|
if([data length] > 0)
|
||||||
[ascii setString:[hexDelegate asciiRepresentation:data]];
|
[hex setString:[[data hexRepresentation] stringByAppendingString:@" "]];
|
||||||
|
else [hex setString:[data hexRepresentation]];
|
||||||
|
[ascii setString:[data asciiRepresentation]];
|
||||||
|
|
||||||
// apply attributes
|
// apply attributes
|
||||||
[[offset textStorage] addAttributes:dictionary range:NSMakeRange(0, [[offset textStorage] length])];
|
[[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;
|
return bytesPerRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSMenu *)copySubmenu
|
||||||
|
{
|
||||||
|
return copySubmenu;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSMenu *)pasteSubmenu
|
- (NSMenu *)pasteSubmenu
|
||||||
{
|
{
|
||||||
return pasteSubmenu;
|
return pasteSubmenu;
|
||||||
@ -328,4 +288,36 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
|||||||
return undoManager;
|
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
|
@end
|
@ -1,34 +1,33 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>Hexadecimal Editor</string>
|
<string>Hexadecimal Editor</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
|
||||||
<string></string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string></string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.nickshanks.resknife.hexadecimal</string>
|
<string>com.nickshanks.resknife.hexadecimal</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string></string>
|
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>BNDL</string>
|
<string>BNDL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string></string>
|
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>ResK</string>
|
<string>ResK</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>0.0.1d1</string>
|
<string>3</string>
|
||||||
<key>NSMainNibFile</key>
|
|
||||||
<string>HexWindow</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>HexWindowController</string>
|
<string>HexWindowController</string>
|
||||||
<key>RKEditedType</key>
|
<key>RKSupportedTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>IsResKnifeDefaultForType</key>
|
||||||
|
<string>YES</string>
|
||||||
|
<key>RKTypeName</key>
|
||||||
<string>Hexadecimal Editor</string>
|
<string>Hexadecimal Editor</string>
|
||||||
|
<key>RKTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</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;
|
PreserveBackups = YES;
|
||||||
Autosave = YES;
|
Autosave = NO;
|
||||||
AutosaveInterval = 5;
|
AutosaveInterval = 5;
|
||||||
DeleteResourceWarning = YES;
|
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>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@function main
|
||||||
|
*/
|
||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
return NSApplicationMain(argc, argv);
|
return NSApplicationMain(argc, argv);
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
resImage = [[NSImage alloc] init];
|
resImage = [[NSImage alloc] init];
|
||||||
|
|
||||||
resData = [[resource data] retain];
|
resData = [[resource data] retain];
|
||||||
planes[0] = (char*) [resData bytes];
|
planes[0] = (unsigned char*) [resData bytes];
|
||||||
|
|
||||||
if( [resType isEqualToString: @"ICN#"] )
|
if( [resType isEqualToString: @"ICN#"] )
|
||||||
{
|
{
|
||||||
|
@ -1,39 +1,36 @@
|
|||||||
ABOUT THE CODE
|
ABOUT THE CODE
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
||||||
WHAT HAPPENS WHEN A TEMPLATE EDITOR IS OPENED FOR A RESOURCE
|
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).
|
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
|
These classes are all subclasses of the common base class Element. For things like
|
||||||
lists, there is a subclass NuTemplateGroupElement from which you can instead subclass to
|
lists, there is a subclass GroupElement from which you can instead subclass to
|
||||||
have some of the work done for you.
|
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
|
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
|
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
|
the copy, which in turn reads data from the TemplateStream and stores it in its instance
|
||||||
variables. For this to work, subclasses of NuTemplateElement *must* implement the NSCopying
|
variables. For this to work, subclasses of Element *must* implement the NSCopying
|
||||||
protocol.
|
protocol.
|
||||||
|
|
||||||
This results in an object hierarchy that describes the entire resource using template fields
|
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.
|
containing the data, which can now be edited, displayed in lists, etc.
|
||||||
|
|
||||||
|
|
||||||
WHAT HAPPENS WHEN THE TEMPLATE EDITOR IS CLOSED
|
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
|
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
|
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.
|
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
|
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.
|
these sub items if they are to be written to disk.
|
||||||
|
|
||||||
|
|
||||||
SPECIAL CASE:LISTS
|
SPECIAL CASE:LISTS
|
||||||
|
|
||||||
When the editor encounters an LSTB element, the LSTB element is called upon to parse its
|
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
|
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.
|
that the equivalent to the "LSTB" item may also update a counter field.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
REVISIONS:
|
REVISIONS:
|
||||||
|
2006-02-05 NS Rewrote plugin.
|
||||||
2003-08-13 UK Finished chapter on lists, added revision history.
|
2003-08-13 UK Finished chapter on lists, added revision history.
|
||||||
2003-08-08 UK Created.
|
2003-08-08 UK Created.
|