mirror of
https://github.com/nickshanks/ResKnife.git
synced 2024-12-22 17:30:15 +00:00
328 lines
11 KiB
Objective-C
328 lines
11 KiB
Objective-C
#import "ApplicationDelegate.h"
|
|
#import "OpenPanelDelegate.h"
|
|
#import "RKDocumentController.h"
|
|
#import "InfoWindowController.h"
|
|
#import "PasteboardWindowController.h"
|
|
#import "PrefsWindowController.h"
|
|
#import "CreateResourceSheetController.h"
|
|
#import "ResourceDocument.h"
|
|
#import "ResourceDataSource.h"
|
|
#import "RKEditorRegistry.h"
|
|
|
|
#import "ResKnifePluginProtocol.h"
|
|
#import "RKSupportResourceRegistry.h"
|
|
|
|
|
|
@implementation ApplicationDelegate
|
|
|
|
- (id)init
|
|
{
|
|
self = [super init];
|
|
[NSApp registerServicesMenuSendTypes:[NSArray arrayWithObject:NSStringPboardType] returnTypes:[NSArray arrayWithObject:NSStringPboardType]];
|
|
return self;
|
|
}
|
|
|
|
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
|
{
|
|
// instanciate my own subclass of NSDocumentController so I can override the open dialog
|
|
[[RKDocumentController alloc] init];
|
|
[RKSupportResourceRegistry scanForSupportResources];
|
|
}
|
|
|
|
/*!
|
|
@method awakeFromNib
|
|
@updated 2003-10-24 NGS: moved icon caching into method called by timer (to speed up app launch time)
|
|
*/
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
// 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"];
|
|
|
|
// initalise an empty icon cache and create timer used to pre-cache a number of common icons
|
|
_icons = [[NSMutableDictionary alloc] init];
|
|
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(precacheIcons:) userInfo:nil repeats:NO];
|
|
|
|
// set default preferences
|
|
[self initUserDefaults];
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[_icons release];
|
|
[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:@"????"];
|
|
[self iconForResourceType:@"CODE"];
|
|
[self iconForResourceType:@"icns"];
|
|
[self iconForResourceType:@"PICT"];
|
|
[self iconForResourceType:@"plst"];
|
|
[self iconForResourceType:@"snd "];
|
|
[self iconForResourceType:@"TEXT"];
|
|
}
|
|
|
|
- (NSArray *)forksForFile:(FSRef *)fileRef
|
|
{
|
|
if(!fileRef) return nil;
|
|
|
|
FSCatalogInfo catalogInfo;
|
|
FSCatalogInfoBitmap whichInfo = kFSCatInfoNodeFlags;
|
|
CatPositionRec forkIterator = { 0 };
|
|
NSMutableArray *forks = [NSMutableArray array];
|
|
|
|
// check we have a file, not a folder
|
|
OSErr error = FSGetCatalogInfo(fileRef, whichInfo, &catalogInfo, NULL, NULL, NULL);
|
|
if(!error && !(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask))
|
|
{
|
|
// iterate over file and populate forks array
|
|
while(error == noErr)
|
|
{
|
|
HFSUniStr255 forkName;
|
|
SInt64 forkSize;
|
|
UInt64 forkPhysicalSize; // used if opening selected fork fails to find empty forks
|
|
|
|
error = FSIterateForks(fileRef, &forkIterator, &forkName, &forkSize, &forkPhysicalSize);
|
|
if(!error)
|
|
{
|
|
NSString *fName = [NSString stringWithCharacters:forkName.unicode length:forkName.length];
|
|
NSNumber *fSize = [NSNumber numberWithLongLong:forkSize];
|
|
NSNumber *fAlloc = [NSNumber numberWithUnsignedLongLong:forkPhysicalSize];
|
|
[forks addObject:[NSDictionary dictionaryWithObjectsAndKeys:fName, @"forkname", fSize, @"forksize", fAlloc, @"forkallocation", nil]];
|
|
}
|
|
else if(error != errFSNoMoreItems)
|
|
{
|
|
NSLog(@"FSIterateForks() error: %d", error);
|
|
}
|
|
}
|
|
}
|
|
else if(error)
|
|
{
|
|
NSLog(@"FSGetCatalogInfo() error: %d", error);
|
|
}
|
|
return forks;
|
|
}
|
|
|
|
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
|
|
{
|
|
#pragma unused(sender)
|
|
NSString *launchAction = [[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchAction"];
|
|
if([launchAction isEqualToString:@"OpenUntitledFile"])
|
|
return YES;
|
|
else if([launchAction isEqualToString:@"DisplayOpenPanel"])
|
|
{
|
|
[[NSDocumentController sharedDocumentController] openDocument:sender];
|
|
return NO;
|
|
}
|
|
else return NO; // should be @"None", but we shall return NO for any other value
|
|
}
|
|
|
|
- (BOOL)application:(NSApplication *)application openFile:(NSString *)file
|
|
{
|
|
#pragma unused(application)
|
|
// bug: check if application was an external editor (e.g. Iconographer) and update existing open file instead
|
|
[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfFile:file display:YES];
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
|
|
{
|
|
#pragma unused(sender)
|
|
return !flag;
|
|
}
|
|
|
|
- (IBAction)showAbout:(id)sender
|
|
{
|
|
// could do with a better about box
|
|
/* NSWindowController *wc = [[NSWindowController alloc] initWithWindowNibName:@"AboutPanel"];
|
|
if([(NSTextView *)[[wc window] initialFirstResponder] readRTFDFromFile:[[NSBundle mainBundle] pathForResource:@"Credits" ofType:@"rtf"]])
|
|
{
|
|
[[wc window] center];
|
|
[[wc window] orderFront:nil];
|
|
}
|
|
else*/ [NSApp orderFrontStandardAboutPanel:sender];
|
|
}
|
|
|
|
- (IBAction)visitWebsite:(id)sender
|
|
{
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://web.nickshanks.com/resknife/"]];
|
|
}
|
|
|
|
- (IBAction)visitSourceforge:(id)sender
|
|
{
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://resknife.sourceforge.net/"]];
|
|
}
|
|
|
|
- (IBAction)emailDeveloper:(id)sender
|
|
{
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"mailto:resknife@nickshanks.com?Subject=Comments,%20Suggestions%20and%20Bug%20Reports"]];
|
|
}
|
|
|
|
- (IBAction)showInfo:(id)sender
|
|
{
|
|
[[InfoWindowController sharedInfoWindowController] showWindow:sender];
|
|
}
|
|
|
|
- (IBAction)showPasteboard:(id)sender
|
|
{
|
|
[[PasteboardWindowController sharedPasteboardWindowController] showWindow:sender];
|
|
}
|
|
|
|
- (IBAction)showPrefs:(id)sender
|
|
{
|
|
[[PrefsWindowController sharedPrefsWindowController] showWindow:sender];
|
|
}
|
|
|
|
- (void)initUserDefaults
|
|
{
|
|
// This should probably be added to NSUserDefaults as a category,
|
|
// since its universally useful. It loads a defaults.plist file
|
|
// from the app wrapper, and then sets the defaults if they don't
|
|
// already exist.
|
|
|
|
NSUserDefaults *defaults;
|
|
NSDictionary *defaultsPlist;
|
|
NSEnumerator *overDefaults;
|
|
id eachDefault;
|
|
|
|
// this isn't required, but saves us a few method calls
|
|
defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
// load the defaults.plist from the app wrapper. This makes it
|
|
// easy to add new defaults just using a text editor instead of
|
|
// hard-coding them into the application
|
|
defaultsPlist = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"defaults" ofType:@"plist"]];
|
|
|
|
// enumerate over all the keys in the dictionary
|
|
overDefaults = [[defaultsPlist allKeys] objectEnumerator];
|
|
while(eachDefault = [overDefaults nextObject])
|
|
{
|
|
// for each key in the dictionary
|
|
// check if there is a value already registered for it
|
|
// and if there isn't, then register the value that was in the file
|
|
if(![defaults stringForKey:eachDefault])
|
|
{
|
|
[defaults setObject:[defaultsPlist objectForKey:eachDefault] forKey:eachDefault];
|
|
}
|
|
}
|
|
|
|
// force the defaults to save to the disk
|
|
[defaults synchronize];
|
|
}
|
|
|
|
- (OpenPanelDelegate *)openPanelDelegate
|
|
{
|
|
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 retrieve 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
|
|
{
|
|
NSImage *icon = nil;
|
|
if([resourceType isEqualToString:@""])
|
|
resourceType = nil;
|
|
|
|
if(resourceType)
|
|
{
|
|
// check if we have image in cache already
|
|
icon = [[self _icons] objectForKey:resourceType]; // valueForKey: raises when the resourceType begins with '@' (e.g. the @GN4 owner resource from Gene!)
|
|
|
|
if(!icon)
|
|
{
|
|
NSString *iconPath = nil;
|
|
|
|
// try to load icon from the default editor for that type
|
|
Class editor = [[RKEditorRegistry defaultRegistry] editorForType:resourceType];
|
|
if(editor)
|
|
{
|
|
// 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)
|
|
{
|
|
iconPath = [[NSBundle mainBundle] pathForResource:resourceType ofType:nil inDirectory:@"Resource Type Icons"];
|
|
if(iconPath)
|
|
icon = [[[NSImage alloc] initWithContentsOfFile:iconPath] autorelease];
|
|
}
|
|
|
|
// try to retrieve from file system using our resource type to file name extension/bundle identifier code
|
|
if(!icon)
|
|
{
|
|
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];
|
|
}
|
|
}
|
|
|
|
// TODO: convert to a UTI and try that
|
|
|
|
// try to retrieve from file system as an OSType code
|
|
if(!icon)
|
|
icon = [[NSWorkspace sharedWorkspace] iconForFileType:[NSString stringWithFormat:@"'%@'", resourceType]];
|
|
|
|
// save the newly retrieved icon in the cache
|
|
if(icon)
|
|
[[self _icons] setObject:icon forKey:resourceType];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we have no resource type, try to get a generic icon - this is what icon represented forks get
|
|
// if(!icon) icon = [NSImage imageNamed:@"NSMysteryDocument"];
|
|
// if(!icon) icon = [[NSWorkspace sharedWorkspace] iconForFileType:@"' '"];
|
|
if(!icon) icon = [[NSWorkspace sharedWorkspace] iconForFileType:[NSString stringWithFormat:@"'%@'", @"????"]];
|
|
}
|
|
|
|
// return the cached icon, or nil if none was found
|
|
return icon;
|
|
}
|
|
|
|
- (NSMutableDictionary *)_icons
|
|
{
|
|
return _icons;
|
|
}
|
|
|
|
- (NSDictionary *)icons
|
|
{
|
|
return [NSDictionary dictionaryWithDictionary:[self _icons]];
|
|
}
|
|
|
|
@end |