mirror of
https://github.com/nickshanks/ResKnife.git
synced 2025-03-21 22:30:46 +00:00
Plugin registry, unique ID determining in "create" sheet, export of resources etc.
This commit is contained in:
parent
7abf1cbb73
commit
1b2cc9ce34
@ -27,6 +27,9 @@
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
NSTableColumn *tableColumn;
|
||||
NSButtonCell *buttonCell;
|
||||
|
||||
// Part of my EvilPlanª to find out how many people use ResKnife and how often!
|
||||
int launchCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"];
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:launchCount + 1 forKey:@"LaunchCount"];
|
||||
@ -38,8 +41,8 @@
|
||||
[icons setObject:[[NSWorkspace sharedWorkspace] iconForFileType:@"icns"] forKey:@"icns"];
|
||||
|
||||
// set up open dialog's aux table view
|
||||
NSTableColumn *tableColumn = [forkTableView tableColumnWithIdentifier:@"parse"];
|
||||
NSButtonCell *buttonCell = [[[NSButtonCell alloc] initTextCell:@""] autorelease];
|
||||
tableColumn = [forkTableView tableColumnWithIdentifier:@"parse"];
|
||||
buttonCell = [[[NSButtonCell alloc] initTextCell:@""] autorelease];
|
||||
[buttonCell setEditable:YES];
|
||||
[buttonCell setButtonType:NSSwitchButton];
|
||||
[tableColumn setDataCell:buttonCell];
|
||||
@ -170,10 +173,10 @@
|
||||
|
||||
/* Don't tell anyone I did this... */
|
||||
|
||||
- (void)setTreatsFilePackagesAsDirectories:(BOOL)flag
|
||||
/*- (void)setTreatsFilePackagesAsDirectories:(BOOL)flag
|
||||
{
|
||||
#pragma unused( flag )
|
||||
_spFlags.treatsFilePackagesAsDirectories = YES;
|
||||
}
|
||||
}*/
|
||||
|
||||
@end
|
@ -5,32 +5,56 @@
|
||||
|
||||
@implementation CreateResourceSheetController
|
||||
|
||||
- (void)controlTextDidChange:(NSNotification *)notification
|
||||
{
|
||||
BOOL enableButton = NO, clash = NO;
|
||||
NSString *type = [typeView stringValue];
|
||||
NSNumber *resID = [NSNumber numberWithInt:[resIDView intValue]];
|
||||
/* -----------------------------------------------------------------------------
|
||||
controlTextDidChange:
|
||||
Someone changed the control ID edit field. Check whether this is
|
||||
a unique ID and appropriately enable the "create" button.
|
||||
|
||||
Check "notification" against being nil, which is how we call it when
|
||||
we need to explicitly update the enabled state of the "create" button.
|
||||
|
||||
|
||||
if( [type length] == 4 && [[resIDView stringValue] length] > 0 )
|
||||
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
|
||||
{
|
||||
BOOL enableButton = NO;
|
||||
NSString *type = [typeView stringValue];
|
||||
NSNumber *resID = [NSNumber numberWithInt:[resIDView intValue]];
|
||||
|
||||
if( [type length] == 4 )
|
||||
{
|
||||
// I could use +[Resource getResourceOfType:andID:inDocument:] != nil, but that would be much slower
|
||||
Resource *resource;
|
||||
NSEnumerator *enumerator = [[[document dataSource] resources] objectEnumerator];
|
||||
while( resource = [enumerator nextObject] )
|
||||
{
|
||||
if( [type isEqualToString:[resource type]] && [resID isEqualToNumber:[resource resID]] )
|
||||
clash = YES;
|
||||
}
|
||||
if( !clash ) enableButton = YES;
|
||||
Resource *resource = [[document dataSource] resourceOfType:type andID:resID];
|
||||
if( resource == nil ) // No resource with that type and ID yet?
|
||||
enableButton = YES;
|
||||
}
|
||||
[createButton setEnabled:enableButton];
|
||||
}
|
||||
|
||||
- (void)showCreateResourceSheet:(ResourceDocument *)sheetDoc
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
showCreateResourceSheet:
|
||||
Show our sheet and set it up before that.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Commented, made it "fake" a popup selection so
|
||||
type field and popup match. Made it suggest an unused
|
||||
resource ID.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(void) showCreateResourceSheet: (ResourceDocument*)sheetDoc
|
||||
{
|
||||
// bug: didEndSelector could be better employed than using the button's targets from interface builder
|
||||
document = sheetDoc;
|
||||
[NSApp beginSheet:[self window] modalForWindow:[document mainWindow] modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
||||
[resIDView setObjectValue: [[document dataSource] uniqueIDForType: [typeView stringValue]]];
|
||||
[self typePopupSelection: typePopup]; // Puts current popup value in text field and updates state of "create" button.
|
||||
}
|
||||
|
||||
- (IBAction)hideCreateResourceSheet:(id)sender
|
||||
@ -55,10 +79,21 @@
|
||||
[NSApp endSheet:[self window]];
|
||||
}
|
||||
|
||||
- (IBAction)typePopupSelection:(id)sender
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
typePopupSelection:
|
||||
Someone chose an item from our "res type" popup menu. Update our
|
||||
edit field to show that.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Commented, made it update state of "create" button..
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(IBAction) typePopupSelection:(id)sender
|
||||
{
|
||||
[typeView setStringValue:[typePopup titleOfSelectedItem]];
|
||||
[typeView selectText:sender];
|
||||
[self controlTextDidChange: nil]; // Make sure "create" button is updated.
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -35,6 +35,7 @@ enum Attributes
|
||||
- (void)updateInfoWindow;
|
||||
- (void)setMainWindow:(NSWindow *)mainWindow;
|
||||
- (IBAction)attributesChanged:(id)sender;
|
||||
- (IBAction)nameChanged: (id)sender;
|
||||
- (void)resourceAttributesDidChange:(NSNotification *)notification;
|
||||
- (void)documentInfoDidChange:(NSNotification *)notification;
|
||||
|
||||
|
@ -40,8 +40,11 @@
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentInfoDidChange:) name:DocumentInfoDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)updateInfoWindow
|
||||
-(void) updateInfoWindow
|
||||
{
|
||||
[nameView setEditable:(selectedResource != nil)];
|
||||
[nameView setDrawsBackground:(selectedResource != nil)];
|
||||
|
||||
if( selectedResource )
|
||||
{
|
||||
[[self window] setTitle:@"Resource Info"];
|
||||
@ -71,8 +74,8 @@
|
||||
[[self window] setTitle:@"Document Info"];
|
||||
[iconView setImage:[NSImage imageNamed:@"Resource file"]];
|
||||
[nameView setStringValue:[currentDocument fileName]? [[currentDocument fileName] lastPathComponent]:[currentDocument displayName]];
|
||||
[[filePropertyForm cellAtIndex:0] setStringValue:@"hi:)"/*[currentDocument creator]*/];
|
||||
[[filePropertyForm cellAtIndex:1] setStringValue:@"helo"/*[currentDocument type]*/];
|
||||
[[filePropertyForm cellAtIndex:0] setStringValue:[currentDocument creator]];
|
||||
[[filePropertyForm cellAtIndex:1] setStringValue:[currentDocument type]];
|
||||
// [[filePropertyForm cellAtIndex:2] setObjectValue:[NSNumber numberWithUnsignedLongLong:dataLogicalSize]];
|
||||
// [[filePropertyForm cellAtIndex:3] setObjectValue:[NSNumber numberWithUnsignedLongLong:rsrcLogicalSize]];
|
||||
[[filePropertyForm cellAtIndex:2] setStringValue:[[NSNumber numberWithUnsignedLongLong:dataLogicalSize] description]];
|
||||
@ -102,6 +105,8 @@
|
||||
|
||||
- (void)selectedResourceChanged:(NSNotification *)notification
|
||||
{
|
||||
if( ![[nameView stringValue] isEqualToString: [selectedResource name]] )
|
||||
[self nameChanged:nameView];
|
||||
selectedResource = [[notification object] selectedItem];
|
||||
[self updateInfoWindow];
|
||||
}
|
||||
@ -119,8 +124,15 @@
|
||||
[selectedResource setAttributes:[NSNumber numberWithShort:number]];
|
||||
}
|
||||
|
||||
-(IBAction) nameChanged: (id)sender
|
||||
{
|
||||
[selectedResource setName: [nameView stringValue]];
|
||||
}
|
||||
|
||||
- (void)resourceAttributesDidChange:(NSNotification *)notification;
|
||||
{
|
||||
if( ![[nameView stringValue] isEqualToString: [selectedResource name]] )
|
||||
[self nameChanged:nameView];
|
||||
[self updateInfoWindow];
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
#import <sys/attr.h>
|
||||
|
||||
struct directoryinfo {
|
||||
ÊÊ unsigned long length;
|
||||
ÊÊ u_int32_t dirid;
|
||||
unsigned long length;
|
||||
u_int32_t dirid;
|
||||
};
|
||||
|
||||
struct dunnowhat
|
||||
@ -25,8 +25,8 @@ struct dunnowhat
|
||||
/* NSTableView data source protocol implementation */
|
||||
- (int)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
NSBrowser *browser = [(NSOpenPanel *)[tableView window] browser];
|
||||
if( [[browser selectedCells] count] == 1 )
|
||||
//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];
|
||||
@ -45,7 +45,7 @@ struct dunnowhat
|
||||
NSLog( @"%d", fileinfo.length );
|
||||
NSLog( @"%d", fileinfo.dirid );
|
||||
*/
|
||||
struct attrlist alist;
|
||||
/*struct attrlist alist;
|
||||
struct directoryinfo dirinfo;
|
||||
char *path = [[browser path] cString];
|
||||
bzero(&alist, sizeof(alist));
|
||||
@ -54,11 +54,11 @@ struct dunnowhat
|
||||
int result = getattrlist(path, &alist, &dirinfo, sizeof(dirinfo), 0);
|
||||
printf("result: %d; directory id: %lu; %s\n", result, dirinfo.dirid, path);
|
||||
|
||||
return 3;
|
||||
return 3;*/
|
||||
}
|
||||
|
||||
// multiple/no selected files, return nothing
|
||||
else return 0;
|
||||
/*else*/ return 0;
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
|
||||
@ -107,7 +107,7 @@ struct dunnowhat
|
||||
|
||||
- (NSBrowser *)browser
|
||||
{
|
||||
return _browser;
|
||||
return nil; //return _browser;
|
||||
}
|
||||
|
||||
@end
|
@ -26,15 +26,19 @@
|
||||
// create the resource & add it to the array
|
||||
NSString *name = pbName;
|
||||
NSString *type;
|
||||
NSNumber *resID;
|
||||
NSNumber *attributes;
|
||||
NSData *data;
|
||||
Resource *resource;
|
||||
NS_DURING
|
||||
type = [currentType substringToIndex:3];
|
||||
NS_HANDLER
|
||||
type = currentType;
|
||||
NS_ENDHANDLER
|
||||
NSNumber *resID = [NSNumber numberWithShort:0];
|
||||
NSNumber *attributes = [NSNumber numberWithShort:0];
|
||||
NSData *data = [pb dataForType:type];
|
||||
Resource *resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data];
|
||||
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
|
||||
}
|
||||
[[self undoManager] enableUndoRegistration];
|
||||
|
44
Cocoa/Classes/RKEditorRegistry.h
Normal file
44
Cocoa/Classes/RKEditorRegistry.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* =============================================================================
|
||||
PROJECT: ResKnife
|
||||
FILE: RKEditorRegistry.h
|
||||
|
||||
PURPOSE:
|
||||
This is a registry where all our resource-editor plugins are looked
|
||||
up and entered in a list, so you can ask for the editor for a specific
|
||||
resource type and it is returned immediately. This registry reads the
|
||||
types a plugin handles from their info.plist. This is better than
|
||||
encoding the type in the plugin file name, as file names are not
|
||||
guaranteed to be on a case-sensitive file system on Mac, and this also
|
||||
allows an editor to register for several resource types.
|
||||
|
||||
AUTHORS: M. Uli Kusterer, witness(at)zathras.de, (c) 2003.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Headers:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "ResKnifePluginProtocol.h"
|
||||
#import "ResKnifeResourceProtocol.h"
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Class interface:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
@interface RKEditorRegistry : NSObject
|
||||
{
|
||||
NSMutableDictionary* typeRegistry; // Private. Use editorForType: to access this.
|
||||
}
|
||||
|
||||
+(RKEditorRegistry*) mainRegistry; // There's usually only one object, and this returns or creates it.
|
||||
|
||||
-(IBAction) scanForPlugins: (id)sender; // Called automatically by mainRegistry.
|
||||
-(Class) editorForType: (NSString*)typeStr; // You probably want to call this.
|
||||
|
||||
|
||||
@end
|
185
Cocoa/Classes/RKEditorRegistry.m
Normal file
185
Cocoa/Classes/RKEditorRegistry.m
Normal file
@ -0,0 +1,185 @@
|
||||
/* =============================================================================
|
||||
PROJECT: ResKnife
|
||||
FILE: RKEditorRegistry.m
|
||||
|
||||
PURPOSE:
|
||||
This is a registry where all our resource-editor plugins are looked
|
||||
up and entered in a list, so you can ask for the editor for a specific
|
||||
resource type and it is returned immediately. This registry reads the
|
||||
types a plugin handles from their info.plist. This is better than
|
||||
encoding the type in the plugin file name, as file names are not
|
||||
guaranteed to be on a case-sensitive file system on Mac, and this also
|
||||
allows an editor to register for several resource types.
|
||||
|
||||
AUTHORS: M. Uli Kusterer, witness(at)zathras.de, (c) 2003.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Headers:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#import "RKEditorRegistry.h"
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Globals:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
RKEditorRegistry* gRKEditorRegistryMainRegistry = nil; // Access through +mainRegistry!
|
||||
|
||||
|
||||
@implementation RKEditorRegistry
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
mainRegistry:
|
||||
Returns the main plugin registry of this application, instantiating
|
||||
it first if there is none yet. As soon as this is instantiated, the
|
||||
plugins are loaded.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
+(RKEditorRegistry*) mainRegistry
|
||||
{
|
||||
if( !gRKEditorRegistryMainRegistry )
|
||||
{
|
||||
gRKEditorRegistryMainRegistry = [[RKEditorRegistry alloc] init];
|
||||
[gRKEditorRegistryMainRegistry scanForPlugins: gRKEditorRegistryMainRegistry];
|
||||
}
|
||||
return gRKEditorRegistryMainRegistry;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
awakeFromNib:
|
||||
Makes sure that if an instance of this is instantiated from a NIB file,
|
||||
it automatically loads the plugins.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(void) awakeFromNib
|
||||
{
|
||||
[self scanForPlugins: self];
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
scanForPlugins:
|
||||
(Re)loads our list of plugins. You can use this as an action for a menu
|
||||
item, if you want.
|
||||
|
||||
This scans the application's internal Plugins folder,
|
||||
~/Library/Application Support/ResKnife/Plugins/ and
|
||||
/Library/Application Support/ResKnife/Plugins/ for plugins that have
|
||||
the extension ".plugin" and implement initWithResource: (which means
|
||||
this won't get into the way if you want to support other kinds of
|
||||
plugins).
|
||||
|
||||
It builds a registry of Class objects in an NSMutableDictionary, where
|
||||
the key is the resource type. If a plugin supports several resource
|
||||
types (as indicated by the RKEditedTypes key in its Info.plist), it
|
||||
will be registered for these types as well. If several plugins register
|
||||
for the same type, the last one loaded wins.
|
||||
|
||||
To instantiate an object from a plugin, see the method below.
|
||||
|
||||
TODO:
|
||||
Currently, Cocoa classes can't be unloaded, which means we're not
|
||||
leaking the NSBundles we load here. However, if this one day shouldn't
|
||||
hold true anymore, we'll want to retain these bundles in our dictionary
|
||||
and do the principalClass thingie in editorForType: instead, which
|
||||
allows us to get rid of the class and its bundle when reloading the
|
||||
plugin list by simply relying on NSMutableDictionary to release it.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(IBAction) scanForPlugins: (id)sender
|
||||
{
|
||||
// TODO: Instead of hard-coding sysPath we should use some FindFolder-like API!
|
||||
Class pluginClass;
|
||||
NSString *appSupport = @"Library/Application Support/ResKnife/Plugins/";
|
||||
NSString *appPath = [[NSBundle mainBundle] builtInPlugInsPath];
|
||||
NSString *userPath = [NSHomeDirectory() stringByAppendingPathComponent:appSupport];
|
||||
NSString *sysPath = [@"/" stringByAppendingPathComponent:appSupport];
|
||||
NSArray *paths = [NSArray arrayWithObjects:appPath, userPath, sysPath, nil];
|
||||
NSEnumerator *pathEnum = [paths objectEnumerator];
|
||||
NSString *path;
|
||||
|
||||
if( typeRegistry )
|
||||
[typeRegistry release];
|
||||
typeRegistry = [[NSMutableDictionary alloc] init];
|
||||
|
||||
while( path = [pathEnum nextObject] )
|
||||
{
|
||||
NSEnumerator *e = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
|
||||
NSString *name;
|
||||
|
||||
NSLog(@"Looking for plugins at %@", path);
|
||||
|
||||
while( name = [e nextObject] )
|
||||
{
|
||||
name = [path stringByAppendingPathComponent:name];
|
||||
NSLog(@"Examining %@", name);
|
||||
if( [[name pathExtension] isEqualToString:@"plugin"] )
|
||||
{
|
||||
NSBundle *plugin = [NSBundle bundleWithPath: name];
|
||||
|
||||
NSLog(@"Identifier %@", [plugin bundleIdentifier]);
|
||||
if( pluginClass = [plugin principalClass] )
|
||||
{
|
||||
NSLog(@"Found plugin: %@", name);
|
||||
if( [pluginClass instancesRespondToSelector:@selector(initWithResource:)] )
|
||||
{
|
||||
NSString *resType;
|
||||
NSArray *types = [[plugin infoDictionary] objectForKey:@"RKEditedTypes"];
|
||||
NSEnumerator *enny;
|
||||
|
||||
if( types == nil )
|
||||
types = [NSArray arrayWithObject: [[plugin infoDictionary] objectForKey:@"RKEditedType"]];
|
||||
|
||||
for( enny = [types objectEnumerator]; resType = [enny nextObject]; )
|
||||
{
|
||||
[typeRegistry setObject:pluginClass forKey:resType];
|
||||
NSLog(@"Registered for type %@.",resType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
editorForType:
|
||||
Looks up the editor for the specified type in our registry of plugins
|
||||
and returns the main class "object" that registered for this type, or
|
||||
Nil if there is none registered for this type.
|
||||
|
||||
Note that the resource type is stored as an NSString, which means it
|
||||
can be longer than four characters (Currently used for looking up the
|
||||
Hexadecimal and Template editors, which are special in that they work
|
||||
with any resource).
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(Class) editorForType: (NSString*)typeStr
|
||||
{
|
||||
Class theClass = [typeRegistry objectForKey: typeStr];
|
||||
if( !theClass )
|
||||
return Nil;
|
||||
|
||||
return theClass;
|
||||
}
|
||||
|
||||
@end
|
@ -16,6 +16,8 @@
|
||||
|
||||
// the actual data
|
||||
NSData *data;
|
||||
|
||||
NSDocument *document; // Our owner.
|
||||
}
|
||||
|
||||
// accessor methods not part of the protocol
|
||||
@ -33,4 +35,7 @@
|
||||
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue;
|
||||
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue data:(NSData *)dataValue;
|
||||
|
||||
-(void) setDocument: (NSDocument*)doc;
|
||||
-(NSDocument*) document; // Resource protocol guarantees this.
|
||||
|
||||
@end
|
||||
|
@ -39,6 +39,7 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue
|
||||
{
|
||||
Resource *resource = [[Resource allocWithZone:[self zone]] initWithType:typeValue andID:resIDValue];
|
||||
@ -156,6 +157,19 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
|
||||
-(void) setDocument: (NSDocument*)doc
|
||||
{
|
||||
document = doc; // It owns us, so don't retain, or we could get a closed loop!
|
||||
}
|
||||
|
||||
|
||||
-(NSDocument*) document
|
||||
{
|
||||
return document;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)representedFork
|
||||
{
|
||||
return representedFork;
|
||||
|
@ -19,8 +19,10 @@
|
||||
- (NSNumber *)uniqueIDForType:(NSString *)type;
|
||||
|
||||
// accessors
|
||||
- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID;
|
||||
- (Resource *)resourceOfType:(NSString *)type withName:(NSString *)name;
|
||||
- (NSArray *)allResourcesOfType:(NSString *)type;
|
||||
-(Resource*) resourceOfType: (NSString*)type andID: (NSNumber*)resID;
|
||||
-(Resource*) resourceOfType: (NSString*)type withName: (NSString*)name;
|
||||
-(NSArray*) allResourcesOfType: (NSString*)type;
|
||||
-(NSArray*) allResourceIDsOfType: (NSString*)type;
|
||||
|
||||
|
||||
@end
|
||||
|
@ -1,6 +1,32 @@
|
||||
/* =============================================================================
|
||||
PROJECT: ResKnife
|
||||
FILE: ResourceDataSource.m
|
||||
|
||||
PURPOSE:
|
||||
Dedicated data source for our resource list. Shares its list of
|
||||
resources with ResourceDocument. I have no idea why Nick did this
|
||||
split, though...
|
||||
|
||||
AUTHORS: Nick Shanks, nick(at)nickshanks.com, (c) ~2001.
|
||||
M. Uli Kusterer, witness(at)zathras.de, (c) 2003.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Added storing document pointer in resource, commented.
|
||||
========================================================================== */
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Headers:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#import "ResourceDataSource.h"
|
||||
#import "ResourceDocument.h"
|
||||
#import "Resource.h"
|
||||
#import <limits.h>
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Notification names:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
NSString *DataSourceWillAddResourceNotification = @"DataSourceWillAddResourceNotification";
|
||||
NSString *DataSourceDidAddResourceNotification = @"DataSourceDidAddResourceNotification";
|
||||
@ -46,6 +72,7 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
|
||||
// it seems very inefficient to reload the entire data source when just adding/removing one item
|
||||
// for large resource files, the data source gets reloaded hundereds of times upon load
|
||||
[resource setDocument:document];
|
||||
[resources addObject:resource];
|
||||
[outlineView reloadData];
|
||||
|
||||
@ -66,17 +93,21 @@ 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
|
||||
}
|
||||
|
||||
- (void)resourceDidChange:(NSNotification *)notification
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
resourceDidChange:
|
||||
Notification from the Resource class that we're registered to. It's
|
||||
sent whenever the resource is "touch"ed.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Commented, made this "touch" the document as well.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(void) resourceDidChange: (NSNotification*)notification
|
||||
{
|
||||
// reload the data for the changed resource
|
||||
[outlineView reloadItem:[notification object]];
|
||||
}
|
||||
|
||||
- (NSNumber *)uniqueIDForType:(NSString *)type
|
||||
{
|
||||
short resID = 128;
|
||||
while( [self resourceOfType:type andID:[NSNumber numberWithShort:resID]] != nil ) resID++;
|
||||
return [NSNumber numberWithShort:resID];
|
||||
[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 */
|
||||
@ -153,4 +184,54 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
|
||||
return [NSArray arrayWithArray:array];
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
allResourceIDsOfType:
|
||||
Returns an NSArray full of NSNumber* objects containing the IDs of all
|
||||
resources of specified type. Used by uniqueIDForType:.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Created based on allResourcesOfType:.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(NSArray*) allResourceIDsOfType: (NSString*)type
|
||||
{
|
||||
Resource *resource;
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
NSEnumerator *enumerator = [resources objectEnumerator];
|
||||
while( resource = [enumerator nextObject] )
|
||||
{
|
||||
if( [[resource type] isEqualToString:type] )
|
||||
[array addObject:[resource resID]];
|
||||
}
|
||||
return [NSArray arrayWithArray:array];
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
uniqueIDForType:
|
||||
Tries to return an unused resource ID for a new resource of specified
|
||||
type. If all IDs are used up (can't really happen, because the resource
|
||||
manager can't take more than 2727 resources per file without crashing,
|
||||
but just in theory...), this will return 128 no matter whether it's
|
||||
used or not.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Created.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(NSNumber*) uniqueIDForType: (NSString*)type
|
||||
{
|
||||
short theID = 128;
|
||||
NSArray *array = [self allResourceIDsOfType: type];
|
||||
|
||||
if( [array count] <= USHRT_MAX )
|
||||
{
|
||||
while( [array containsObject: [NSNumber numberWithShort:theID]] )
|
||||
theID++;
|
||||
}
|
||||
|
||||
return [NSNumber numberWithShort: theID];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -29,6 +29,9 @@
|
||||
- (IBAction)playSound:(id)sender;
|
||||
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished;
|
||||
|
||||
-(IBAction) exportResourceToFile: (id)sender;
|
||||
-(IBAction) exportResourceToImageFile: (id)sender;
|
||||
|
||||
- (IBAction)copy:(id)sender;
|
||||
- (IBAction)paste:(id)sender;
|
||||
- (void)pasteResources:(NSArray *)pastedResources;
|
||||
|
@ -1,3 +1,25 @@
|
||||
/* =============================================================================
|
||||
PROJECT: ResKnife
|
||||
FILE: ResourceDocument.m
|
||||
|
||||
PURPOSE:
|
||||
This is a ResKnife document (I still write Resurrection occasionally,
|
||||
sorry Nick...), it handles loading, display etc. of resources.
|
||||
|
||||
It uses a separate object as the data source for its outline view,
|
||||
though, ResourceDataSource. I'd better ask Nick why.
|
||||
|
||||
AUTHORS: Nick Shanks, nick(at)nickshanks.com, (c) ~2001.
|
||||
M. Uli Kusterer, witness(at)zathras.de, (c) 2003.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Added support for plugin registry, commented.
|
||||
========================================================================== */
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Headers:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#import "ResourceDocument.h"
|
||||
#import "ResourceDataSource.h"
|
||||
#import "ResourceNameCell.h"
|
||||
@ -8,10 +30,17 @@
|
||||
#import "NSOutlineView-SelectedItems.h"
|
||||
|
||||
#import "ResKnifePluginProtocol.h"
|
||||
#import "RKEditorRegistry.h"
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Notification names:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
NSString *DocumentInfoWillChangeNotification = @"DocumentInfoWillChangeNotification";
|
||||
NSString *DocumentInfoDidChangeNotification = @"DocumentInfoDidChangeNotification";
|
||||
|
||||
|
||||
extern NSString *RKResourcePboardType;
|
||||
|
||||
@implementation ResourceDocument
|
||||
@ -19,9 +48,13 @@ extern NSString *RKResourcePboardType;
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if( !self )
|
||||
return nil;
|
||||
toolbarItems = [[NSMutableDictionary alloc] init];
|
||||
resources = [[NSMutableArray alloc] init];
|
||||
fork = nil;
|
||||
creator = [@"ResK" retain];
|
||||
type = [@"rsrc" retain];
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -31,6 +64,8 @@ extern NSString *RKResourcePboardType;
|
||||
if( fork ) DisposePtr( (Ptr) fork );
|
||||
[resources release];
|
||||
[toolbarItems release];
|
||||
[type release];
|
||||
[creator release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@ -111,6 +146,16 @@ extern NSString *RKResourcePboardType;
|
||||
else if( [item action] == @selector(openResourcesInTemplate:) ) return selectedRows > 0;
|
||||
else if( [item action] == @selector(openResourcesWithOtherTemplate:) ) return selectedRows > 0;
|
||||
else if( [item action] == @selector(openResourcesAsHex:) ) return selectedRows > 0;
|
||||
else if( [item action] == @selector(exportResourceToImageFile:) )
|
||||
{
|
||||
Class edClass;
|
||||
|
||||
if( selectedRows < 1 )
|
||||
return NO;
|
||||
|
||||
edClass = [[RKEditorRegistry mainRegistry] editorForType: [resource type]];
|
||||
return [edClass respondsToSelector:@selector(imageForImageFileExport:)];
|
||||
}
|
||||
else if( [item action] == @selector(playSound:) ) return selectedRows == 1 && [[resource type] isEqualToString:@"snd "];
|
||||
else if( [item action] == @selector(revertResourceToSaved:) ) return selectedRows == 1 && [resource isDirty];
|
||||
else return [super validateMenuItem:item];
|
||||
@ -126,6 +171,7 @@ static NSString *RKEditItemIdentifier = @"com.nickshanks.resknife.toolbar.edit"
|
||||
static NSString *RKEditHexItemIdentifier = @"com.nickshanks.resknife.toolbar.edithex";
|
||||
static NSString *RKSaveItemIdentifier = @"com.nickshanks.resknife.toolbar.save";
|
||||
static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.showinfo";
|
||||
static NSString *RKExportItemIdentifier = @"com.ulikusterer.resknife.toolbar.export";
|
||||
|
||||
- (void)setupToolbar:(NSWindowController *)windowController
|
||||
{
|
||||
@ -135,6 +181,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[toolbarItems removeAllObjects]; // just in case this method is called more than once per document (which it shouldn't be!)
|
||||
|
||||
item = [[NSToolbarItem alloc] initWithItemIdentifier:RKCreateItemIdentifier];
|
||||
[item autorelease];
|
||||
[item setLabel:NSLocalizedString(@"Create", nil)];
|
||||
[item setPaletteLabel:NSLocalizedString(@"Create", nil)];
|
||||
[item setToolTip:NSLocalizedString(@"Create New Resource", nil)];
|
||||
@ -142,9 +189,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(showCreateResourceSheet:)];
|
||||
[toolbarItems setObject:item forKey:RKCreateItemIdentifier];
|
||||
[item release];
|
||||
|
||||
item = [[NSToolbarItem alloc] initWithItemIdentifier:RKDeleteItemIdentifier];
|
||||
[item autorelease];
|
||||
[item setLabel:NSLocalizedString(@"Delete", nil)];
|
||||
[item setPaletteLabel:NSLocalizedString(@"Delete", nil)];
|
||||
[item setToolTip:NSLocalizedString(@"Delete Selected Resource", nil)];
|
||||
@ -152,9 +199,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(clear:)];
|
||||
[toolbarItems setObject:item forKey:RKDeleteItemIdentifier];
|
||||
[item release];
|
||||
|
||||
item = [[NSToolbarItem alloc] initWithItemIdentifier:RKEditItemIdentifier];
|
||||
[item autorelease];
|
||||
[item setLabel:NSLocalizedString(@"Edit", nil)];
|
||||
[item setPaletteLabel:NSLocalizedString(@"Edit", nil)];
|
||||
[item setToolTip:NSLocalizedString(@"Edit Resource In Default Editor", nil)];
|
||||
@ -162,9 +209,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(openResources:)];
|
||||
[toolbarItems setObject:item forKey:RKEditItemIdentifier];
|
||||
[item release];
|
||||
|
||||
item = [[NSToolbarItem alloc] initWithItemIdentifier:RKEditHexItemIdentifier];
|
||||
[item autorelease];
|
||||
[item setLabel:NSLocalizedString(@"Edit Hex", nil)];
|
||||
[item setPaletteLabel:NSLocalizedString(@"Edit Hex", nil)];
|
||||
[item setToolTip:NSLocalizedString(@"Edit Resource As Hexadecimal", nil)];
|
||||
@ -172,9 +219,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(openResourcesAsHex:)];
|
||||
[toolbarItems setObject:item forKey:RKEditHexItemIdentifier];
|
||||
[item release];
|
||||
|
||||
item = [[NSToolbarItem alloc] initWithItemIdentifier:RKSaveItemIdentifier];
|
||||
[item autorelease];
|
||||
[item setLabel:NSLocalizedString(@"Save", nil)];
|
||||
[item setPaletteLabel:NSLocalizedString(@"Save", nil)];
|
||||
[item setToolTip:[NSString stringWithFormat:NSLocalizedString(@"Save To %@ Fork", nil), !fork? NSLocalizedString(@"Data", nil) : NSLocalizedString(@"Resource", nil)]];
|
||||
@ -182,9 +229,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(saveDocument:)];
|
||||
[toolbarItems setObject:item forKey:RKSaveItemIdentifier];
|
||||
[item release];
|
||||
|
||||
item = [[NSToolbarItem alloc] initWithItemIdentifier:RKShowInfoItemIdentifier];
|
||||
[item autorelease];
|
||||
[item setLabel:NSLocalizedString(@"Show Info", nil)];
|
||||
[item setPaletteLabel:NSLocalizedString(@"Show Info", nil)];
|
||||
[item setToolTip:NSLocalizedString(@"Show Resource Information Window", nil)];
|
||||
@ -192,14 +239,23 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[item setTarget:[NSApp delegate]];
|
||||
[item setAction:@selector(showInfo:)];
|
||||
[toolbarItems setObject:item forKey:RKShowInfoItemIdentifier];
|
||||
[item release];
|
||||
|
||||
item = [[NSToolbarItem alloc] initWithItemIdentifier:RKExportItemIdentifier];
|
||||
[item autorelease];
|
||||
[item setLabel:NSLocalizedString(@"Export Data", nil)];
|
||||
[item setPaletteLabel:NSLocalizedString(@"Export Resource Data", nil)];
|
||||
[item setToolTip:NSLocalizedString(@"Export the resource's data to a file", nil)];
|
||||
[item setImage:[NSImage imageNamed:@"Export"]];
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(exportResourceToFile:)];
|
||||
[toolbarItems setObject:item forKey:RKExportItemIdentifier];
|
||||
|
||||
if( [windowController window] == mainWindow )
|
||||
{
|
||||
NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:RKToolbarIdentifier] autorelease];
|
||||
|
||||
// set toolbar properties
|
||||
[toolbar setVisible:NO];
|
||||
[toolbar setVisible:YES];
|
||||
[toolbar setAutosavesConfiguration:YES];
|
||||
[toolbar setAllowsUserCustomization:YES];
|
||||
[toolbar setDisplayMode:NSToolbarDisplayModeDefault];
|
||||
@ -217,12 +273,12 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
|
||||
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return [NSArray arrayWithObjects:RKCreateItemIdentifier, RKEditItemIdentifier, RKEditHexItemIdentifier, NSToolbarSeparatorItemIdentifier, RKSaveItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, nil];
|
||||
return [NSArray arrayWithObjects:RKCreateItemIdentifier, RKShowInfoItemIdentifier, RKDeleteItemIdentifier, NSToolbarSeparatorItemIdentifier, RKEditItemIdentifier, RKEditHexItemIdentifier, NSToolbarSeparatorItemIdentifier, RKSaveItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, nil];
|
||||
}
|
||||
|
||||
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return [NSArray arrayWithObjects:RKCreateItemIdentifier, RKDeleteItemIdentifier, RKEditItemIdentifier, RKEditHexItemIdentifier, RKSaveItemIdentifier, RKShowInfoItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
|
||||
return [NSArray arrayWithObjects:RKCreateItemIdentifier, RKDeleteItemIdentifier, RKEditItemIdentifier, RKEditHexItemIdentifier, RKSaveItemIdentifier, RKExportItemIdentifier, RKShowInfoItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
|
||||
}
|
||||
|
||||
- (BOOL)validateToolbarItem:(NSToolbarItem *)item
|
||||
@ -235,6 +291,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
else if( [identifier isEqualToString:RKDeleteItemIdentifier] ) valid = selectedRows > 0;
|
||||
else if( [identifier isEqualToString:RKEditItemIdentifier] ) valid = selectedRows > 0;
|
||||
else if( [identifier isEqualToString:RKEditHexItemIdentifier] ) valid = selectedRows > 0;
|
||||
else if( [identifier isEqualToString:RKExportItemIdentifier] ) valid = selectedRows > 0;
|
||||
else if( [identifier isEqualToString:RKSaveItemIdentifier] ) valid = [self isDocumentEdited];
|
||||
else if( [identifier isEqualToString:NSToolbarPrintItemIdentifier] ) valid = YES;
|
||||
|
||||
@ -286,18 +343,29 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[self openResourceAsHex:resource];
|
||||
}
|
||||
|
||||
- (void)openResourceUsingEditor:(Resource *)resource
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
openResourceUsingEditor:
|
||||
Open an editor for the specified Resource instance. This looks up
|
||||
the editor to use in the plugin registry and then instantiates an
|
||||
editor object, handing it the resource. If there is no editor for this
|
||||
type registered, it falls back to the template editor, which in turn
|
||||
uses the hex editor as a fallback.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Changed to use plugin registry instead of file name.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(void) openResourceUsingEditor: (Resource*)resource
|
||||
{
|
||||
// #warning openResourceUsingEditor: shortcuts to NovaTools !!
|
||||
// opens resource in template using TMPL resource with name templateName
|
||||
// NSBundle *editor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"NovaTools.plugin"]];
|
||||
NSBundle *editor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@ Editor.plugin", [resource type]]]];
|
||||
Class editorClass = [[RKEditorRegistry mainRegistry] editorForType: [resource type]];
|
||||
|
||||
// open the resources, passing in the template to use
|
||||
if( editor /*&& [[editor principalClass] respondsToSelector:@selector(initWithResource:)]*/ )
|
||||
if( editorClass )
|
||||
{
|
||||
// bug: I alloc a plug instance here, but have no idea where I should dealloc it, perhaps the plug ought to call [self autorelease] when it's last window is closed?
|
||||
id plug = [(id <ResKnifePluginProtocol>)[[editor principalClass] alloc] initWithResource:resource];
|
||||
// update: doug says window controllers automatically release themselves when their window is closed.
|
||||
id plug = [(id <ResKnifePluginProtocol>)[editorClass alloc] initWithResource:resource];
|
||||
if( plug ) return;
|
||||
}
|
||||
|
||||
@ -305,21 +373,34 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[self openResource:resource usingTemplate:[resource type]];
|
||||
}
|
||||
|
||||
- (void)openResource:(Resource *)resource usingTemplate:(NSString *)templateName
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
openResource:usingTemplate:
|
||||
Open a template editor for the specified Resource instance. This looks
|
||||
up the template editor in the plugin registry and then instantiates an
|
||||
editor object, handing it the resource and the template resource to use.
|
||||
If there is no template editor registered, or there is no template for
|
||||
this resource type, it falls back to the hex editor.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Changed to use plugin registry instead of file name.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(void) openResource: (Resource*)resource usingTemplate: (NSString*)templateName
|
||||
{
|
||||
// opens resource in template using TMPL resource with name templateName
|
||||
NSBundle *templateEditor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"Template Editor.plugin"]];
|
||||
Class editorClass = [[RKEditorRegistry mainRegistry] editorForType: @"Template Editor"];
|
||||
|
||||
// bug: this checks EVERY DOCUMENT for template resources (might not be desired)
|
||||
// bug: it doesn't, however, check the application's resource map for a matching template!
|
||||
// TODO: this checks EVERY DOCUMENT for template resources (might not be desired)
|
||||
// TODO: it doesn't, however, check the application's resource map for a matching template!
|
||||
Resource *tmpl = [Resource resourceOfType:@"TMPL" withName:[resource type] inDocument:nil];
|
||||
|
||||
// open the resources, passing in the template to use
|
||||
if( tmpl /*&& [[templateEditor principalClass] respondsToSelector:@selector(initWithResources:)]*/ )
|
||||
if( tmpl && editorClass )
|
||||
{
|
||||
// bug: I alloc a plug instance here, but have no idea where I should dealloc it, perhaps the plug ought to call [self autorelease] when it's last window is closed?
|
||||
// update: doug says window controllers automatically release themselves when their window is closed.
|
||||
NSWindowController *plugController = [(id <ResKnifePluginProtocol>)[[templateEditor principalClass] alloc] initWithResources:resource, tmpl, nil];
|
||||
NSWindowController *plugController = [(id <ResKnifeTemplatePluginProtocol>)[editorClass alloc] initWithResources:resource, tmpl, nil];
|
||||
if( plugController ) return;
|
||||
}
|
||||
|
||||
@ -327,13 +408,30 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[self openResourceAsHex:resource];
|
||||
}
|
||||
|
||||
- (void)openResourceAsHex:(Resource *)resource
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
openResourceAsHex:
|
||||
Open a hex editor for the specified Resource instance. This looks
|
||||
up the hexadecimal editor in the plugin registry and then instantiates an
|
||||
editor object, handing it the resource.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Changed to use plugin registry instead of file name.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(void) openResourceAsHex: (Resource*)resource
|
||||
{
|
||||
NSBundle *hexEditor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"Hexadecimal Editor.plugin"]];
|
||||
Class editorClass = [[RKEditorRegistry mainRegistry] editorForType: @"Hexadecimal Editor"];
|
||||
// bug: I alloc a plug instance here, but have no idea where I should dealloc it, perhaps the plug ought to call [self autorelease] when it's last window is closed?
|
||||
NSWindowController *plugController = [(id <ResKnifePluginProtocol>)[[hexEditor principalClass] alloc] initWithResource:resource];
|
||||
// update: doug says window controllers automatically release themselves when their window is closed.
|
||||
NSWindowController *plugController = [(id <ResKnifePluginProtocol>)[editorClass alloc] initWithResource:resource];
|
||||
}
|
||||
|
||||
|
||||
// TODO: These two should really be moved to a 'snd ' editor, but first we'd
|
||||
// need to extend the plugin protocol to call the class so it can add
|
||||
// such menu items. Of course, we could just make the 'snd ' editor
|
||||
// have a button in its window that plays the sound.
|
||||
- (IBAction)playSound:(id)sender
|
||||
{
|
||||
// bug: can only cope with one selected item
|
||||
@ -500,7 +598,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
if( [outlineView numberOfSelectedRows] > 1 )
|
||||
[[self undoManager] setActionName:NSLocalizedString(@"Delete Resources", nil)];
|
||||
|
||||
// deselct resources (otherwise other resources move into selected rows!)
|
||||
// deselect resources (otherwise other resources move into selected rows!)
|
||||
[outlineView deselectAll:self];
|
||||
}
|
||||
|
||||
@ -513,18 +611,39 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
return YES;
|
||||
}*/
|
||||
|
||||
- (BOOL)readFromFile:(NSString *)fileName ofType:(NSString *)type
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
readFromFile:ofType:
|
||||
Open the specified file and read its resources. This first tries to
|
||||
load the resources from the res fork, and failing that tries the data
|
||||
fork.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Commented.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(BOOL) readFromFile: (NSString*)fileName ofType: (NSString*)fileKind
|
||||
{
|
||||
BOOL succeeded = NO;
|
||||
OSStatus error = noErr;
|
||||
HFSUniStr255 *resourceForkName = (HFSUniStr255 *) NewPtrClear( sizeof(HFSUniStr255) );
|
||||
FSRef *fileRef = (FSRef *) NewPtrClear( sizeof(FSRef) );
|
||||
SInt16 fileRefNum = 0;
|
||||
BOOL succeeded = NO;
|
||||
OSStatus error = noErr;
|
||||
HFSUniStr255 *resourceForkName = (HFSUniStr255 *) NewPtrClear( sizeof(HFSUniStr255) ); // This may be saved away in the instance variable "fork" to keep track of which fork our resources are in.
|
||||
FSRef *fileRef = (FSRef *) NewPtrClear( sizeof(FSRef) );
|
||||
SInt16 fileRefNum = 0;
|
||||
FSCatalogInfo info = { 0 };
|
||||
|
||||
// open fork with resources in it
|
||||
error = FSPathMakeRef( [fileName cString], fileRef, nil );
|
||||
error = FSGetResourceForkName( resourceForkName );
|
||||
SetResLoad( false ); // don't load "preload" resources
|
||||
|
||||
[type release];
|
||||
[creator release];
|
||||
|
||||
error = FSGetCatalogInfo( fileRef, kFSCatInfoFinderInfo, &info, nil, nil, nil );
|
||||
type = [[NSString stringWithCString: &((FileInfo*)info.finderInfo)->fileType length:4] retain];
|
||||
creator = [[NSString stringWithCString: &((FileInfo*)info.finderInfo)->fileCreator length:4] retain];
|
||||
|
||||
// Try res fork first:
|
||||
error = FSOpenResourceFile( fileRef, resourceForkName->length, (UniChar *) &resourceForkName->unicode, fsRdPerm, &fileRefNum);
|
||||
if( error ) // try to open data fork instead
|
||||
{
|
||||
@ -540,7 +659,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
|
||||
// read the resources (without spawning thousands of undos for resource creation)
|
||||
[[self undoManager] disableUndoRegistration];
|
||||
if( fileRefNum && !error )
|
||||
if( fileRefNum && error == noErr )
|
||||
succeeded = [self readResourceMap:fileRefNum];
|
||||
else if( !fileRefNum )
|
||||
{
|
||||
@ -551,7 +670,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[[self undoManager] enableUndoRegistration];
|
||||
|
||||
// tidy up loose ends
|
||||
if( !fork ) DisposePtr( (Ptr) resourceForkName ); // only delete if we're not saving it
|
||||
if( !fork ) DisposePtr( (Ptr) resourceForkName ); // only delete if we're not saving it to "fork" instance var.
|
||||
if( fileRefNum ) FSClose( fileRefNum );
|
||||
DisposePtr( (Ptr) fileRef );
|
||||
return succeeded;
|
||||
@ -570,31 +689,41 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
It is perfectly legal in ResKnife to read in forks of these names when accessing a shared NTFS drive from a server running SFM. */
|
||||
|
||||
[resource setRepresentedFork:forkName];
|
||||
[resource setDocument:self];
|
||||
[resources insertObject:resource atIndex:0];
|
||||
return YES;
|
||||
}
|
||||
else return NO;
|
||||
}
|
||||
|
||||
- (BOOL)readResourceMap:(SInt16)fileRefNum
|
||||
-(BOOL) readResourceMap: (SInt16)fileRefNum
|
||||
{
|
||||
OSStatus error = noErr;
|
||||
unsigned short n;
|
||||
unsigned short i;
|
||||
SInt16 oldResFile = CurResFile();
|
||||
UseResFile( fileRefNum );
|
||||
|
||||
for( unsigned short i = 1; i <= Count1Types(); i++ )
|
||||
for( i = 1; i <= Count1Types(); i++ )
|
||||
{
|
||||
ResType resType;
|
||||
unsigned short j;
|
||||
|
||||
Get1IndType( &resType, i );
|
||||
n = Count1Resources( resType );
|
||||
for( unsigned short j = 1; j <= n; j++ )
|
||||
for( j = 1; j <= n; j++ )
|
||||
{
|
||||
Str255 nameStr;
|
||||
long sizeLong;
|
||||
short resIDShort;
|
||||
short attrsShort;
|
||||
Handle resourceHandle;
|
||||
Str255 nameStr;
|
||||
long sizeLong;
|
||||
short resIDShort;
|
||||
short attrsShort;
|
||||
Handle resourceHandle;
|
||||
NSString *name;
|
||||
NSString *type;
|
||||
NSNumber *resID;
|
||||
NSNumber *attributes;
|
||||
NSData *data;
|
||||
Resource *resource;
|
||||
|
||||
resourceHandle = Get1IndResource( resType, j );
|
||||
error = ResError();
|
||||
@ -611,12 +740,13 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
HLockHi( resourceHandle );
|
||||
|
||||
// create the resource & add it to the array
|
||||
NSString *name = [NSString stringWithCString:&nameStr[1] length:nameStr[0]];
|
||||
NSString *type = [NSString stringWithCString:(char *) &resType length:4];
|
||||
NSNumber *resID = [NSNumber numberWithShort:resIDShort];
|
||||
NSNumber *attributes = [NSNumber numberWithShort:attrsShort];
|
||||
NSData *data = [NSData dataWithBytes:*resourceHandle length:sizeLong];
|
||||
Resource *resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data];
|
||||
name = [NSString stringWithCString:&nameStr[1] length:nameStr[0]];
|
||||
type = [NSString stringWithCString:(char *) &resType length:4];
|
||||
resID = [NSNumber numberWithShort:resIDShort];
|
||||
attributes = [NSNumber numberWithShort:attrsShort];
|
||||
data = [NSData dataWithBytes:*resourceHandle length:sizeLong];
|
||||
resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data];
|
||||
[resource setDocument:self];
|
||||
[resources addObject:resource]; // array retains resource
|
||||
|
||||
HUnlock( resourceHandle );
|
||||
@ -678,33 +808,57 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
- (BOOL)writeResourceMap:(SInt16)fileRefNum
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
writeResourceMap:
|
||||
Writes all resources (except the ones representing other forks of the
|
||||
file) to the specified resource file.
|
||||
|
||||
REVISIONS:
|
||||
2003-08-01 UK Swiss national holiday, and I'm stuck in Germany...
|
||||
Commented, changed to use enumerator instead of
|
||||
objectAtIndex.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-(BOOL) writeResourceMap: (SInt16)fileRefNum
|
||||
{
|
||||
OSStatus error = noErr;
|
||||
unsigned long i;
|
||||
SInt16 oldResFile = CurResFile();
|
||||
OSStatus error = noErr;
|
||||
NSEnumerator* enny;
|
||||
Resource *resource;
|
||||
|
||||
// Make the resource file current:
|
||||
SInt16 oldResFile = CurResFile();
|
||||
UseResFile( fileRefNum );
|
||||
|
||||
for( i = 0; i < [resources count]; i++ )
|
||||
// Loop over all our resources:
|
||||
for( enny = [resources objectEnumerator]; resource = [enny nextObject]; )
|
||||
{
|
||||
Resource *resource = [resources objectAtIndex:i];
|
||||
if( [resource representedFork] != nil ) continue;
|
||||
|
||||
Str255 nameStr;
|
||||
ResType resType;
|
||||
short resIDShort = [[resource resID] shortValue];
|
||||
short attrsShort = [[resource attributes] shortValue];
|
||||
Handle resourceHandle = NewHandleClear( [[resource data] length] );
|
||||
short resIDShort;
|
||||
short attrsShort;
|
||||
Handle resourceHandle;
|
||||
|
||||
// Resource represents another fork in the file? Skip it.
|
||||
if( [resource representedFork] != nil ) continue;
|
||||
|
||||
resIDShort = [[resource resID] shortValue];
|
||||
attrsShort = [[resource attributes] shortValue];
|
||||
resourceHandle = NewHandleClear( [[resource data] length] );
|
||||
|
||||
// Unicode name -> P-String:
|
||||
nameStr[0] = [[resource name] cStringLength];
|
||||
BlockMoveData( [[resource name] cString], &nameStr[1], nameStr[0] );
|
||||
|
||||
// Type string to ResType:
|
||||
[[resource type] getCString:(char *) &resType maxLength:4];
|
||||
|
||||
// NSData to resource data Handle:
|
||||
HLockHi( resourceHandle );
|
||||
[[resource data] getBytes:*resourceHandle];
|
||||
HUnlock( resourceHandle );
|
||||
|
||||
// Now that everything's converted, write it to our file:
|
||||
AddResource( resourceHandle, resType, resIDShort, nameStr );
|
||||
if( ResError() == addResFailed )
|
||||
{
|
||||
@ -720,7 +874,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
}
|
||||
}
|
||||
|
||||
// save resource map and clean up
|
||||
// Save resource map and clean up:
|
||||
UseResFile( oldResFile );
|
||||
return error? NO:YES;
|
||||
}
|
||||
@ -807,4 +961,77 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
|
||||
[[self undoManager] setActionName:NSLocalizedString( @"Change Creator & Type", nil)];
|
||||
}
|
||||
|
||||
|
||||
-(void) exportDataPanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
|
||||
{
|
||||
NSData* data = contextInfo;
|
||||
[data autorelease];
|
||||
|
||||
if( returnCode == NSOKButton )
|
||||
[data writeToFile:[sheet filename] atomically: YES];
|
||||
}
|
||||
|
||||
|
||||
-(void) exportImagePanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
|
||||
{
|
||||
NSImage* img = contextInfo;
|
||||
[img autorelease];
|
||||
|
||||
if( returnCode == NSOKButton )
|
||||
{
|
||||
NSData* data = [img TIFFRepresentation];
|
||||
[data writeToFile:[sheet filename] atomically: YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(IBAction) exportResourceToFile: (id)sender
|
||||
{
|
||||
Resource* resource = (Resource*) [outlineView selectedItem];
|
||||
NSData* theData;
|
||||
Class edClass = [[RKEditorRegistry mainRegistry] editorForType: [resource type]];
|
||||
NSString* extension = [resource type];
|
||||
NSSavePanel* panel;
|
||||
NSString* fName;
|
||||
|
||||
if( [edClass respondsToSelector:@selector(dataForFileExport:)] )
|
||||
theData = [edClass dataForFileExport: resource];
|
||||
else
|
||||
theData = [resource data];
|
||||
|
||||
if( [edClass respondsToSelector:@selector(extensionForFileExport:)] )
|
||||
extension = [edClass extensionForFileExport];
|
||||
|
||||
panel = [NSSavePanel savePanel];
|
||||
fName = [[resource name] stringByAppendingFormat: @".%@", extension];
|
||||
|
||||
[panel beginSheetForDirectory:nil file:fName modalForWindow:mainWindow modalDelegate:self
|
||||
didEndSelector:@selector(exportDataPanelDidEnd:returnCode:contextInfo:) contextInfo:[theData retain]];
|
||||
}
|
||||
|
||||
|
||||
-(IBAction) exportResourceToImageFile: (id)sender
|
||||
{
|
||||
Resource* resource = (Resource*) [outlineView selectedItem];
|
||||
NSImage* theData;
|
||||
Class edClass = [[RKEditorRegistry mainRegistry] editorForType: [resource type]];
|
||||
NSString* extension = @"tiff";
|
||||
NSSavePanel* panel;
|
||||
NSString* fName;
|
||||
|
||||
if( ![edClass respondsToSelector:@selector(imageForImageFileExport:)] )
|
||||
return;
|
||||
|
||||
theData = [edClass imageForImageFileExport: resource];
|
||||
|
||||
if( [edClass respondsToSelector:@selector(extensionForImageFileExport:)] )
|
||||
extension = [edClass extensionForFileExport];
|
||||
|
||||
panel = [NSSavePanel savePanel];
|
||||
fName = [[resource name] stringByAppendingFormat: @".%@", extension];
|
||||
|
||||
[panel beginSheetForDirectory:nil file:fName modalForWindow:mainWindow modalDelegate:self
|
||||
didEndSelector:@selector(exportImagePanelDidEnd:returnCode:contextInfo:) contextInfo:[theData retain]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -21,8 +21,9 @@
|
||||
int dataLength = [data length], bytesPerRow = [controller bytesPerRow];
|
||||
int rows = (dataLength / bytesPerRow) + ((dataLength % bytesPerRow)? 1:0);
|
||||
NSMutableString *representation = [NSMutableString string];
|
||||
int row;
|
||||
|
||||
for( int row = 0; row < rows; row++ )
|
||||
for( row = 0; row < rows; row++ )
|
||||
[representation appendFormat:@"%08lX:", row * bytesPerRow];
|
||||
|
||||
return representation;
|
||||
@ -35,11 +36,14 @@
|
||||
char buffer[bytesPerRow*3 +1], hex1, hex2;
|
||||
char *bytes = (char *) [data bytes];
|
||||
NSMutableString *representation = [NSMutableString string];
|
||||
int row;
|
||||
|
||||
// calculate bytes
|
||||
for( int row = 0; row < rows; row++ )
|
||||
for( row = 0; row < rows; row++ )
|
||||
{
|
||||
for( int addr = 0; addr < bytesPerRow; addr++ )
|
||||
int addr;
|
||||
|
||||
for( addr = 0; addr < bytesPerRow; addr++ )
|
||||
{
|
||||
if( currentByte < dataLength )
|
||||
{
|
||||
@ -82,11 +86,14 @@
|
||||
char buffer[bytesPerRow +1];
|
||||
char *bytes = (char *) [data bytes];
|
||||
NSMutableString *representation = [NSMutableString string];
|
||||
int row;
|
||||
|
||||
// calculate bytes
|
||||
for( int row = 0; row < rows; row++ )
|
||||
for( row = 0; row < rows; row++ )
|
||||
{
|
||||
for( int addr = 0; addr < bytesPerRow; addr++ )
|
||||
int addr;
|
||||
|
||||
for( addr = 0; addr < bytesPerRow; addr++ )
|
||||
{
|
||||
if( currentByte < dataLength )
|
||||
{
|
||||
@ -121,7 +128,9 @@
|
||||
NSString *result;
|
||||
unsigned long bytesEncoded = ([data length] + 1) / 3;
|
||||
char *buffer = (char *) malloc( bytesEncoded ), hex1, hex2;
|
||||
for( int i = 0; i < bytesEncoded; i++ )
|
||||
int i;
|
||||
|
||||
for( i = 0; i < bytesEncoded; i++ )
|
||||
{
|
||||
hex1 = ((char *)[data bytes])[3*i];
|
||||
hex2 = ((char *)[data bytes])[3*i+1];
|
||||
|
@ -264,6 +264,7 @@ static NSRange draggedRange;
|
||||
NSPasteboard *pb = [sender draggingPasteboard];
|
||||
NSData *pastedData = [pb dataForType:NSStringPboardType];
|
||||
int charIndex = [self _insertionGlyphIndexForDrag:sender];
|
||||
NSRange selection;
|
||||
|
||||
// convert hex string to data
|
||||
if( [sender draggingSource] == [[self delegate] hex] )
|
||||
@ -293,7 +294,7 @@ static NSRange draggedRange;
|
||||
[self editData:[[[self window] windowController] data] replaceBytesInRange:NSMakeRange(charIndex,0) withData:pastedData];
|
||||
|
||||
// set the new selection/insertion point
|
||||
NSRange selection = [self rangeForUserTextChange];
|
||||
selection = [self rangeForUserTextChange];
|
||||
selection.location -= draggedRange.length;
|
||||
selection.length = draggedRange.length;
|
||||
[self setSelectedRange:selection];
|
||||
@ -327,8 +328,9 @@ static NSRange draggedRange;
|
||||
|
||||
if( self == (id) [[self delegate] hex] )
|
||||
{
|
||||
int i;
|
||||
// bug: iteration through each character in string is broken, paste not yet mapped to this function
|
||||
for( int i = 0; i < [string cStringLength]; i++ )
|
||||
for( i = 0; i < [string cStringLength]; i++ )
|
||||
{
|
||||
char typedChar = [string characterAtIndex:i];
|
||||
if( typedChar >= 0x30 && typedChar <= 0x39 ) typedChar -= 0x30; // 0 to 9
|
||||
|
@ -47,11 +47,6 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource )
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResources:(id)newResource, ...
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
@ -1,14 +1,60 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ResKnifeResourceProtocol.h"
|
||||
|
||||
/* Your plug-in's principle class must implement initWithResource: else it won't be loaded by ResKnife (so neh-neh!), all other methods are optional */
|
||||
|
||||
/* Your plug-in's principal class must implement initWithResource: else it
|
||||
won't be loaded by ResKnife (so neh-neh!), all other methods are optional,
|
||||
and thus declared in ResKnifeInformalPluginProtocol. */
|
||||
@protocol ResKnifePluginProtocol
|
||||
|
||||
/*! @function initWithResource:
|
||||
* @abstract Your plug-in is inited with this call. This allows immediate access to the resource you are about to edit, and with this information you can set up different windows, etc.
|
||||
/*! @method initWithResource:
|
||||
* @abstract Your plug-in is inited with this call. This allows immediate
|
||||
access to the resource you are about to edit, and with this
|
||||
information you can set up different windows, etc.
|
||||
*/
|
||||
- (id)initWithResource:(id <ResKnifeResourceProtocol>)newResource;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/* Optional methods your plugin may implement to provide additional
|
||||
functionality: */
|
||||
|
||||
@interface ResKnifeInformalPluginProtocol
|
||||
|
||||
/*! @method dataForFileExport:
|
||||
@abstract Return the data to be saved to disk when your resource is
|
||||
exported to a file. By default the host application substitutes
|
||||
the raw resource data if you don't implement this. The idea is
|
||||
that this export function is non-lossy, i.e. only override this
|
||||
if there is a format that is a 100% equivalent to your data. */
|
||||
+(NSData*) dataForFileExport: (id <ResKnifeResourceProtocol>)theRes;
|
||||
/*! @method extensionForFileExport:
|
||||
@abstract If you implement dataForFileExport, return a string here that
|
||||
provides the proper file extension for your file. By default the
|
||||
host application substitutes the resource type here. */
|
||||
+(NSString*) extensionForFileExport: (id <ResKnifeResourceProtocol>)theRes;
|
||||
|
||||
/*! @method imageForImageFileExport:
|
||||
@abstract Return the image to be saved to disk when your resource is
|
||||
exported to an image file. If your resource contains image
|
||||
data, this is your opportunity to export it to a well-known
|
||||
image format. This will be a lossy conversion to a TIFF
|
||||
file. */
|
||||
+(NSImage*) imageForImageFileExport: (id <ResKnifeResourceProtocol>)theRes;
|
||||
/*! @method extensionForImageFileExport:
|
||||
@abstract If you implement imageForImageFileExport, return a string here that
|
||||
provides the proper file extension for your file. By default the
|
||||
host application substitutes "tiff" here. */
|
||||
+(NSString*) extensionForImageFileExport: (id <ResKnifeResourceProtocol>)theRes;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/* If you're implementing a template editor, you should implement this
|
||||
extended protocol instead of the regular plugin protocol: */
|
||||
|
||||
@protocol ResKnifeTemplatePluginProtocol <ResKnifePluginProtocol>
|
||||
|
||||
- (id)initWithResources:(id <ResKnifeResourceProtocol>)newResource, ...;
|
||||
|
||||
@end
|
@ -1,22 +1,57 @@
|
||||
/* =============================================================================
|
||||
PROJECT: ResKnife
|
||||
FILE: ResKnifeResourceProtocol.h
|
||||
|
||||
PURPOSE: This protocol wraps up whatever implementation the host
|
||||
application (i.e. ResKnife) uses for resources in a way that
|
||||
every editor can get enough information about the resource
|
||||
being edited.
|
||||
|
||||
Or in Nick's immortal words (which I found only *after* I had
|
||||
written the stuff above):
|
||||
|
||||
This protocol allows your plug to interrogate a resource to
|
||||
find out information about it.
|
||||
|
||||
AUTHORS: Nick Shanks, nick(at)nickshanks.com, (c) ~2001.
|
||||
M. Uli Kusterer, witness(at)zathras.de, (c) 2003.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Added document accessor, commented.
|
||||
========================================================================== */
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Headers:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/* This protocol allows your plug to interrogate a resource to find out information about it. */
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Protocol:
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
@protocol ResKnifeResourceProtocol
|
||||
|
||||
- (void)touch;
|
||||
- (BOOL)isDirty;
|
||||
- (NSString *)name;
|
||||
- (void)setName:(NSString *)newName;
|
||||
- (NSString *)type;
|
||||
- (void)setType:(NSString *)newType;
|
||||
- (NSNumber *)resID;
|
||||
- (void)setResID:(NSNumber *)newResID;
|
||||
- (NSNumber *)attributes;
|
||||
- (void)setAttributes:(NSNumber *)newAttributes;
|
||||
- (NSNumber *)size;
|
||||
- (NSData *)data;
|
||||
- (void)setData:(NSData *)newData;
|
||||
-(void) touch;
|
||||
-(BOOL) isDirty;
|
||||
|
||||
-(NSString*) name;
|
||||
-(void) setName: (NSString*)newName;
|
||||
|
||||
-(NSString*) type;
|
||||
-(void) setType: (NSString*)newType;
|
||||
-(NSNumber*) resID;
|
||||
-(void) setResID: (NSNumber*)newResID;
|
||||
|
||||
-(NSNumber*) attributes;
|
||||
-(void) setAttributes: (NSNumber*)newAttributes;
|
||||
|
||||
-(NSNumber*) size;
|
||||
-(NSData*) data;
|
||||
-(void) setData: (NSData*)newData;
|
||||
|
||||
-(NSDocument*) document; // Owner of this resource. Useful for looking for resources in same file as yours.
|
||||
|
||||
// These methods are used to retrieve resources other than the one you're editing.
|
||||
// Passing a document of nil will indicate to search in all open documents.
|
||||
@ -31,8 +66,11 @@
|
||||
|
||||
@end
|
||||
|
||||
// Resource notifications
|
||||
// See note in Notifications.m about usage
|
||||
/* -----------------------------------------------------------------------------
|
||||
Resource Notifications:
|
||||
See note in Notifications.m about usage.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
extern NSString *ResourceWillChangeNotification;
|
||||
extern NSString *ResourceNameWillChangeNotification;
|
||||
extern NSString *ResourceTypeWillChangeNotification;
|
||||
|
@ -3,7 +3,7 @@
|
||||
#import "ResKnifePluginProtocol.h"
|
||||
#import "ResKnifeResourceProtocol.h"
|
||||
|
||||
@interface TemplateWindowController : NSWindowController <ResKnifePluginProtocol>
|
||||
@interface TemplateWindowController : NSWindowController <ResKnifePluginProtocol, ResKnifeTemplatePluginProtocol>
|
||||
{
|
||||
IBOutlet NSView *containerView;
|
||||
|
||||
|
@ -171,9 +171,11 @@
|
||||
// while( currentTemplateElement = [enumerator nextObject] )
|
||||
while( position < [[resource size] unsignedLongValue] )
|
||||
{
|
||||
unsigned long type;
|
||||
|
||||
currentTemplateElement = [tmpl objectAtIndex:n];
|
||||
n++, c++;
|
||||
unsigned long type = [currentTemplateElement typeAsLong];
|
||||
type = [currentTemplateElement typeAsLong];
|
||||
resourceElement = [[currentTemplateElement copy] autorelease];
|
||||
NSLog( @"tmpl element = %@; position = %d", currentTemplateElement, position );
|
||||
switch( type )
|
||||
|
BIN
Cocoa/Resources/Export.tiff
Normal file
BIN
Cocoa/Resources/Export.tiff
Normal file
Binary file not shown.
6
Cocoa/main.m
Normal file
6
Cocoa/main.m
Normal file
@ -0,0 +1,6 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, argv);
|
||||
}
|
@ -2,7 +2,8 @@
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
#pragma options align=packed
|
||||
#pragma options align=mac68k
|
||||
//#pragma options align=packed // TODO: This doesn't compile in PB (but it does in xCode).
|
||||
// see http://developer.apple.com/techpubs/macosx/DeveloperTools/MachORuntime/2rt_powerpc_abi/PowerPC_Data_Alignment.html
|
||||
// align=reset is at the bottom of the file.
|
||||
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
- (id)initWithResource:(id <ResKnifeResourceProtocol>)newResource
|
||||
{
|
||||
NSString *tempPrefix;
|
||||
NSString *tempSuffix;
|
||||
NSString *tempStart;
|
||||
|
||||
self = [self initWithWindowNibName:@"char"];
|
||||
if( !self ) return nil;
|
||||
|
||||
@ -66,9 +70,9 @@
|
||||
cash = [[NSNumber alloc] initWithLong:charRec->startCash];
|
||||
kills = [[NSNumber alloc] initWithShort:charRec->startKills];
|
||||
date = [[NSCalendarDate alloc] initWithYear:charRec->startYear month:charRec->startMonth day:charRec->startDay hour:0 minute:0 second:0 timeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
|
||||
NSString *tempPrefix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Prefix length:16] encoding:NSMacOSRomanStringEncoding] autorelease];
|
||||
tempPrefix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Prefix length:16] encoding:NSMacOSRomanStringEncoding] autorelease];
|
||||
prefix = [[NSString alloc] initWithCString:[tempPrefix cString] length:[tempPrefix cStringLength]];
|
||||
NSString *tempSuffix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Suffix length:16] encoding:NSMacOSRomanStringEncoding] autorelease];
|
||||
tempSuffix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Suffix length:16] encoding:NSMacOSRomanStringEncoding] autorelease];
|
||||
suffix = [[NSString alloc] initWithCString:[tempSuffix cString] length:[tempSuffix cStringLength]];
|
||||
start1 = [[NSNumber alloc] initWithShort:charRec->startSystem[0]];
|
||||
start2 = [[NSNumber alloc] initWithShort:charRec->startSystem[1]];
|
||||
@ -91,7 +95,7 @@
|
||||
introDelay2 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[1]];
|
||||
introDelay3 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[2]];
|
||||
introDelay4 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[3]];
|
||||
NSString *tempStart = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->OnStart length:256] encoding:NSMacOSRomanStringEncoding] autorelease];
|
||||
tempStart = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->OnStart length:256] encoding:NSMacOSRomanStringEncoding] autorelease];
|
||||
onStart = [[NSString alloc] initWithCString:[tempStart cString] length:[tempStart cStringLength]];
|
||||
|
||||
// rotating image
|
||||
@ -162,6 +166,8 @@
|
||||
|
||||
- (void)update
|
||||
{
|
||||
NSData *stringData;
|
||||
|
||||
// principal character
|
||||
[principalCharButton setState:principalChar];
|
||||
|
||||
@ -207,7 +213,7 @@
|
||||
[introPictField4 setObjectValue:[pictureDataSource stringValueForResID:introPict4]];
|
||||
[introTextField setObjectValue:[descriptionDataSource stringValueForResID:introText]];
|
||||
|
||||
NSData *stringData = [(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"desc" value:@"" table:@"Resource Types"] andID:introText inDocument:nil] data];
|
||||
stringData = [(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"desc" value:@"" table:@"Resource Types"] andID:introText inDocument:nil] data];
|
||||
if( stringData != nil )
|
||||
{
|
||||
[introTextView setString:[[[NSString alloc] initWithData:stringData encoding:NSMacOSRomanStringEncoding] autorelease]];
|
||||
|
@ -1 +1 @@
|
||||
#undef __STDC_VERSION__
|
||||
//#undef __STDC_VERSION__
|
Loading…
x
Reference in New Issue
Block a user