2001-10-19 19:41:13 +00:00
# import "ResourceDocument.h"
2002-02-14 23:24:53 +00:00
# import "ResourceDataSource.h"
2002-02-07 03:45:43 +00:00
# import "ResourceNameCell.h"
2002-02-23 03:40:24 +00:00
# import "Resource.h"
2008-07-31 20:27:55 +00:00
# import "ApplicationDelegate.h"
# import "OpenPanelDelegate.h"
# import "OutlineViewDelegate.h"
# import "InfoWindowController.h"
2002-05-31 17:31:41 +00:00
# import "PrefsWindowController.h"
2002-02-07 03:45:43 +00:00
# import "CreateResourceSheetController.h"
2008-07-31 20:27:55 +00:00
# import "NGSCategories.h"
# import "../Categories/NSString-FSSpec.h"
# import "../Categories/NSOutlineView-SelectedItems.h"
2001-10-19 19:41:13 +00:00
2008-07-31 20:27:55 +00:00
# import "../Plug-Ins/ResKnifePluginProtocol.h"
2003-08-01 22:23:50 +00:00
# import "RKEditorRegistry.h"
2002-03-31 12:00:02 +00:00
NSString * DocumentInfoWillChangeNotification = @ "DocumentInfoWillChangeNotification" ;
NSString * DocumentInfoDidChangeNotification = @ "DocumentInfoDidChangeNotification" ;
2002-11-13 03:35:54 +00:00
extern NSString * RKResourcePboardType ;
2001-10-19 19:41:13 +00:00
@ implementation ResourceDocument
- ( id ) init
{
self = [ super init ] ;
2008-07-31 20:27:55 +00:00
if ( ! self ) return nil ;
2002-04-30 23:44:23 +00:00
toolbarItems = [ [ NSMutableDictionary alloc ] init ] ;
2002-02-02 11:31:28 +00:00
resources = [ [ NSMutableArray alloc ] init ] ;
2002-03-21 04:02:26 +00:00
fork = nil ;
2008-07-31 20:27:55 +00:00
creator = [ [ @ "ResK" dataUsingEncoding : NSMacOSRomanStringEncoding ] retain ] ; // should I be calling - setCreator & - setType here instead ?
type = [ [ @ "rsrc" dataUsingEncoding : NSMacOSRomanStringEncoding ] retain ] ;
2001-10-19 19:41:13 +00:00
return self ;
}
- ( void ) dealloc
{
2002-02-14 23:24:53 +00:00
[ [ NSNotificationCenter defaultCenter ] removeObserver : self ] ;
2008-07-31 20:27:55 +00:00
if ( fork ) DisposePtr ( ( Ptr ) fork ) ;
2001-10-19 19:41:13 +00:00
[ resources release ] ;
2002-04-30 23:44:23 +00:00
[ toolbarItems release ] ;
2003-08-01 22:23:50 +00:00
[ type release ] ;
[ creator release ] ;
2001-10-19 19:41:13 +00:00
[ super dealloc ] ;
}
2002-02-07 03:45:43 +00:00
# pragma mark -
2008-07-31 20:27:55 +00:00
# pragma mark File Management
/ * !
@ method readFromFile : ofType :
@ abstract Open the specified file and read its resources .
@ description 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 .
@ author Nicholas Shanks
@ updated 2003 -11 -08 NGS : Now handles opening user - selected forks .
* /
- ( BOOL ) readFromFile : ( NSString * ) fileName ofType : ( NSString * ) fileKind
{
BOOL succeeded = NO ;
OSStatus error = noErr ;
FSRef * fileRef = ( FSRef * ) NewPtrClear ( sizeof ( FSRef ) ) ;
SInt16 fileRefNum = 0 ;
OpenPanelDelegate * openPanelDelegate = [ ( ApplicationDelegate * ) [ NSApp delegate ] openPanelDelegate ] ;
// bug : need to handle error better here
error = FSPathMakeRef ( ( const UInt8 * ) [ fileName fileSystemRepresentation ] , fileRef , nil ) ;
if ( error ) return NO ;
// find out which fork to parse
if ( NSAppKitVersionNumber < 700.0 || ! [ openPanelDelegate readOpenPanelForFork ] )
{
// display second dialog to ask user to select a fork , pre -10.3 or if open command did not come via the open dialog
// bug : unimplemented - always tells app to try resource fork first
fork = ( HFSUniStr255 * ) NewPtrClear ( sizeof ( HFSUniStr255 ) ) ;
error = FSGetResourceForkName ( fork ) ;
if ( error ) return NO ;
}
else
{
// get selected fork from open panel , 10.3 +
int row = [ [ openPanelDelegate forkTableView ] selectedRow ] ;
NSString * selectedFork = [ ( NSDictionary * ) [ [ openPanelDelegate forks ] objectAtIndex : row ] valueForKey : @ "forkname" ] ;
fork = ( HFSUniStr255 * ) NewPtrClear ( sizeof ( HFSUniStr255 ) ) ;
fork -> length = ( [ selectedFork length ] < 255 ) ? [ selectedFork length ] : 255 ;
if ( fork -> length > 0 )
[ selectedFork getCharacters : fork -> unicode range : NSMakeRange ( 0 , fork -> length ) ] ;
else fork -> unicode [ 0 ] = 0 ;
// clear so next document doesn ' t get confused
[ openPanelDelegate setReadOpenPanelForFork : NO ] ;
}
NSArray * forks = [ ( ApplicationDelegate * ) [ NSApp delegate ] forksForFile : fileRef ] ;
// attempt to open fork user selected as a resource map
SetResLoad ( false ) ; // don ' t load "preload" resources
error = FSOpenResourceFile ( fileRef , fork -> length , ( UniChar * ) & fork -> unicode , fsRdPerm , & fileRefNum ) ;
if ( error || ! fileRefNum )
{
// if opening the user - selected fork fails , try to open resource fork instead
error = FSGetResourceForkName ( fork ) ;
if ( error ) return NO ;
/ * HFSUniStr255 * rfork ;
error = FSGetResourceForkName ( rfork ) ;
if ( error ) return NO ;
bool checkFork = true ;
if ( FSCreateStringFromHFSUniStr ) // 10.4 only
{
if ( CFStringCompare ( FSCreateStringFromHFSUniStr ( NULL , fork ) , FSCreateStringFromHFSUniStr ( NULL , rfork ) , 0 ) = = NSOrderedSame )
checkFork = false ; // skip checking resource fork if it ' s the one the user chose
else fork = rfork ;
}
if ( checkFork )
* / error = FSOpenResourceFile ( fileRef , fork -> length , ( UniChar * ) & fork -> unicode , fsRdPerm , & fileRefNum ) ;
if ( error || ! fileRefNum )
{
// if opening the resource fork fails , try to open data fork instead
error = FSGetDataForkName ( fork ) ;
if ( error ) return NO ;
error = FSOpenResourceFile ( fileRef , fork -> length , ( UniChar * ) & fork -> unicode , fsRdPerm , & fileRefNum ) ;
if ( error || ! fileRefNum )
{
// bug : should check fork the user selected is empty before trying data fork
NSNumber * fAlloc = [ [ forks firstObjectReturningValue : [ NSString stringWithCharacters : fork -> unicode length : fork -> length ] forKey : @ "forkname" ] valueForKey : @ "forkallocation" ] ;
if ( [ fAlloc unsignedLongLongValue ] > 0 )
{
// data fork is not empty , check resource fork
error = FSGetResourceForkName ( fork ) ;
if ( error ) return NO ;
fAlloc = [ [ forks firstObjectReturningValue : [ NSString stringWithCharacters : fork -> unicode length : fork -> length ] forKey : @ "forkname" ] valueForKey : @ "forkallocation" ] ;
if ( [ fAlloc unsignedLongLongValue ] > 0 )
{
// resource fork is not empty either , give up ( ask user for a fork ? )
NSLog ( @ "Could not find existing map nor create a new map in either the data or resource forks! Aborting." ) ;
return NO ;
}
}
// note that map needs initalising on first save
_createFork = YES ;
}
}
}
SetResLoad ( true ) ; // restore resource loading as soon as is possible
if ( ! _createFork )
{
// disable undos during resource creation and setting of the creator and type
[ [ self undoManager ] disableUndoRegistration ] ;
// then read resources from the selected fork
succeeded = [ self readResourceMap : fileRefNum ] ;
// get creator and type
FSCatalogInfo info ;
error = FSGetCatalogInfo ( fileRef , kFSCatInfoFinderInfo , & info , nil , nil , nil ) ;
if ( ! error )
{
[ self setType : [ NSData dataWithBytes : & ( ( FileInfo * ) info . finderInfo ) -> fileType length : 4 ] ] ;
[ self setCreator : [ NSData dataWithBytes : & ( ( FileInfo * ) info . finderInfo ) -> fileCreator length : 4 ] ] ;
}
// restore undos
[ [ self undoManager ] enableUndoRegistration ] ;
}
else succeeded = YES ;
// now read all other forks as streams
NSString * forkName ;
NSEnumerator * forkEnumerator = [ forks objectEnumerator ] ;
NSString * selectedFork = [ NSString stringWithCharacters : fork -> unicode length : fork -> length ] ;
while ( forkName = [ [ forkEnumerator nextObject ] valueForKey : @ "forkname" ] )
{
// check current fork is not the fork we ' re going to parse
if ( ! [ forkName isEqualToString : selectedFork ] )
[ self readFork : forkName asStreamFromFile : fileRef ] ;
}
// tidy up loose ends
if ( fileRefNum ) FSClose ( fileRefNum ) ;
DisposePtr ( ( Ptr ) fileRef ) ;
return succeeded ;
}
/ * !
@ method readFork : asStreamFromFile :
@ author Nicholas Shanks
@ updated 2003 -11 -08 NGS : Now handles opening user - selected forks .
@ description Note : there is a 2 GB limit to the size of forks that can be read in due to < tt > FSReaadFork ( ) < / tt > taking a 32 - bit buffer length value .
* /
- ( BOOL ) readFork : ( NSString * ) forkName asStreamFromFile : ( FSRef * ) fileRef
{
if ( ! fileRef ) return NO ;
/ * NTFS Note : When running SFM ( Services for Macintosh ) a Windows NT - based system ( including 2000 & XP ) serving NTFS - formatted drives stores Mac resource forks in a stream named "AFP_Resource" . The finder info / attributes are stored in a stream called "AFP_AfpInfo" . The default data fork stream is called "$DATA" and any of these can be accessed thus : "c:\filename.txt:forkname" . Finder comments are stored in a stream called "Comments" .
As a result , ResKnife prohibits creation of forks with the following names : "" ( empty string , Mac data fork name ) ,
"$DATA" ( NTFS data fork name ) ,
"AFP_Resource" , "AFP_AfpInfo" and "Comments" .
It is perfectly legal in ResKnife to read in forks of these names when accessing a shared NTFS drive via SMB . The server does not need to be running SFM since the file requests will appear to be coming from a PC . If the files are accessed via AFP on a server running SFM , SFM will automatically convert the files ( and truncate the name to 31 chars ) . * /
// translate NSString into HFSUniStr255 - - in 10.4 this can be done with FSGetHFSUniStrFromString
HFSUniStr255 uniForkName = { 0 } ;
uniForkName . length = ( [ forkName length ] < 255 ) ? [ forkName length ] : 255 ;
if ( uniForkName . length > 0 )
[ forkName getCharacters : uniForkName . unicode range : NSMakeRange ( 0 , uniForkName . length ) ] ;
else uniForkName . unicode [ 0 ] = 0 ;
// get fork length and create empty buffer , bug : only sizeof ( size_t ) bytes long
ByteCount forkLength = ( ByteCount ) [ [ [ [ ( ApplicationDelegate * ) [ NSApp delegate ] forksForFile : fileRef ] firstObjectReturningValue : forkName forKey : @ "forkname" ] valueForKey : @ "forksize" ] unsignedLongValue ] ;
void * buffer = malloc ( forkLength ) ;
if ( ! buffer ) return NO ;
// read fork contents into buffer , bug : assumes no errors
SInt16 forkRefNum ;
FSOpenFork ( fileRef , uniForkName . length , uniForkName . unicode , fsRdPerm , & forkRefNum ) ;
FSReadFork ( forkRefNum , fsFromStart , 0 , forkLength , buffer , & forkLength ) ;
FSCloseFork ( forkRefNum ) ;
// create data
NSData * data = [ NSData dataWithBytesNoCopy : buffer length : forkLength freeWhenDone : YES ] ;
if ( ! data ) return NO ;
// create resource
Resource * resource = [ Resource resourceOfType : @ "" andID : 0 withName : forkName andAttributes : 0 data : data ] ;
if ( ! resource ) return NO ;
// customise fork name for default data & resource forks - bug : this should really be in resource data source ! !
HFSUniStr255 resourceForkName ;
OSErr error = FSGetResourceForkName ( & resourceForkName ) ;
if ( ! error && [ [ resource name ] isEqualToString : @ "" ] ) // bug : should use FSGetDataForkName ( )
[ resource _setName : NSLocalizedString ( @ "Data Fork" , nil ) ] ;
else if ( ! error && [ [ resource name ] isEqualToString : [ NSString stringWithCharacters : resourceForkName . unicode length : resourceForkName . length ] ] )
[ resource _setName : NSLocalizedString ( @ "Resource Fork" , nil ) ] ;
[ resource setRepresentedFork : forkName ] ;
[ resources addObject : resource ] ;
return YES ;
}
- ( BOOL ) readResourceMap : ( SInt16 ) fileRefNum
{
OSStatus error = noErr ;
SInt16 oldResFile = CurResFile ( ) ;
UseResFile ( fileRefNum ) ;
for ( unsigned short i = 1 ; i <= Count1Types ( ) ; i + + )
{
ResType resType ;
Get1IndType ( & resType , i ) ;
ResType swappedType = EndianS32_NtoB ( resType ) ; // Swapped type for use as string ( types are treated as numbers by the resource manager and swapped on Intel ) .
unsigned short n = Count1Resources ( resType ) ;
for ( unsigned short j = 1 ; j <= n ; j + + )
{
Handle resourceHandle = Get1IndResource ( resType , j ) ;
error = ResError ( ) ;
if ( error ! = noErr )
{
NSLog ( @ "Error %d reading resource map..." , error ) ;
UseResFile ( oldResFile ) ;
return NO ;
}
Str255 nameStr ;
short resIDShort ;
GetResInfo ( resourceHandle , & resIDShort , & resType , nameStr ) ;
long sizeLong = GetResourceSizeOnDisk ( resourceHandle ) ;
short attrsShort = GetResAttrs ( resourceHandle ) ;
HLockHi ( resourceHandle ) ;
// cool : "The advantage of obtaining a method<6F> s implementation and calling it as a function is that you can invoke the implementation multiple times within a loop, or similar C construct, without the overhead of Objective-C messaging."
// create the resource & add it to the array
NSString * name = [ [ NSString alloc ] initWithBytes : & nameStr [ 1 ] length : nameStr [ 0 ] encoding : NSMacOSRomanStringEncoding ] ;
NSString * resType = [ [ NSString alloc ] initWithBytes : ( char * ) & swappedType length : 4 encoding : NSMacOSRomanStringEncoding ] ;
NSNumber * resID = [ NSNumber numberWithShort : resIDShort ] ;
NSNumber * attributes = [ NSNumber numberWithShort : attrsShort ] ;
NSData * data = [ NSData dataWithBytes : * resourceHandle length : sizeLong ] ;
Resource * resource = [ Resource resourceOfType : resType andID : resID withName : name andAttributes : attributes data : data ] ;
[ resource setDocumentName : [ self displayName ] ] ;
[ resources addObject : resource ] ; // array retains resource
[ name release ] ;
[ resType release ] ;
HUnlock ( resourceHandle ) ;
ReleaseResource ( resourceHandle ) ;
}
}
// save resource map and clean up
UseResFile ( oldResFile ) ;
return YES ;
}
/ * !
@ pending Uli ' s changed this routine - see what I had and unify the two
@ pending Doesn ' t write correct type / creator info - always ResKnife ' s !
* /
- ( BOOL ) writeToFile : ( NSString * ) fileName ofType : ( NSString * ) type
{
OSStatus error = noErr ;
SInt16 fileRefNum = 0 ;
FSRef * parentRef = ( FSRef * ) NewPtrClear ( sizeof ( FSRef ) ) ;
FSRef * fileRef = ( FSRef * ) NewPtrClear ( sizeof ( FSRef ) ) ;
// create and open file for writing
// bug : doesn ' t set the cat info to the same as the old file
unichar * uniname = ( unichar * ) NewPtrClear ( sizeof ( unichar ) * 256 ) ;
[ [ fileName lastPathComponent ] getCharacters : uniname ] ;
error = FSPathMakeRef ( ( const UInt8 * ) [ [ fileName stringByDeletingLastPathComponent ] UTF8String ] , parentRef , nil ) ;
if ( fork )
error = FSCreateResourceFile ( parentRef , [ [ fileName lastPathComponent ] length ] , ( UniChar * ) uniname , kFSCatInfoNone , NULL , fork -> length , ( UniChar * ) & fork -> unicode , fileRef , NULL ) ;
else error = FSCreateResourceFile ( parentRef , [ [ fileName lastPathComponent ] length ] , ( UniChar * ) uniname , kFSCatInfoNone , NULL , 0 , NULL , fileRef , NULL ) ;
// write any data streams to file
BOOL succeeded = [ self writeForkStreamsToFile : fileName ] ;
// FSRef * fileRef = [ fileName createFSRef ] ;
/ * error = FSPathMakeRef ( ( const UInt8 * ) [ fileName UTF8String ] , fileRef , nil ) ;
if ( _createFork )
{
error = FSCreateResourceFork ( fileRef , fork -> length , ( UniChar * ) & fork -> unicode , 0 ) ;
_createFork = NO ;
}
* /
if ( ! error )
{
// set creator & type
// bug : due to a bug in AppKit , the temporary file that we are writing to ( in / var / tmp , managed by NSDocument ) does not get it ' s creator code copied over to the new document ( it sets the new document ' s to nil ) . this timer sets the creator code after we have returned to the main loop and the buggy Apple code has been bypassed .
[ NSTimer scheduledTimerWithTimeInterval : 0.0 target : self selector : @ selector ( setTypeCreatorAfterSave : ) userInfo : nil repeats : NO ] ;
// open fork as resource map
if ( fork )
error = FSOpenResourceFile ( fileRef , fork -> length , ( UniChar * ) & fork -> unicode , fsWrPerm , & fileRefNum ) ;
else error = FSOpenResourceFile ( fileRef , 0 , NULL , fsWrPerm , & fileRefNum ) ;
}
// else NSLog ( @ "error creating resource fork. (error=%d, spec=%d, ref=%d, parent=%d)" , error , fileSpec , fileRef , parentRef ) ;
else NSLog ( @ "error creating resource fork. (error=%d, ref=%d)" , error , fileRef ) ;
// write resource array to file
if ( fileRefNum && ! error )
succeeded = [ self writeResourceMap : fileRefNum ] ;
// tidy up loose ends
if ( fileRefNum ) FSClose ( fileRefNum ) ;
DisposePtr ( ( Ptr ) fileRef ) ;
// update info window
[ [ InfoWindowController sharedInfoWindowController ] updateInfoWindow ] ;
return succeeded ;
}
- ( BOOL ) writeForkStreamsToFile : ( NSString * ) fileName
{
// try and get an FSRef
OSStatus error ;
FSRef * fileRef = [ fileName createFSRef ] , * parentRef = nil ;
if ( ! fileRef )
{
parentRef = ( FSRef * ) NewPtrClear ( sizeof ( FSRef ) ) ;
fileRef = ( FSRef * ) NewPtrClear ( sizeof ( FSRef ) ) ;
unichar * uniname = ( unichar * ) NewPtrClear ( sizeof ( unichar ) * 256 ) ;
[ [ fileName lastPathComponent ] getCharacters : uniname ] ;
error = FSPathMakeRef ( ( const UInt8 * ) [ [ fileName stringByDeletingLastPathComponent ] UTF8String ] , parentRef , nil ) ;
if ( error ) return NO ;
error = FSCreateFileUnicode ( parentRef , 0 , NULL , kFSCatInfoNone , NULL , fileRef , NULL ) ;
if ( error || ! fileRef ) return NO ;
}
Resource * resource ;
NSEnumerator * enumerator = [ resources objectEnumerator ] ;
while ( resource = [ enumerator nextObject ] )
{
// if the resource object represents an actual resource , skip it
if ( [ resource representedFork ] = = nil ) continue ;
unichar * uniname = ( unichar * ) NewPtrClear ( sizeof ( unichar ) * 256 ) ;
[ [ resource representedFork ] getCharacters : uniname ] ;
SInt16 forkRefNum = 0 ;
error = FSOpenFork ( fileRef , [ [ resource representedFork ] length ] , ( UniChar * ) uniname , fsWrPerm , & forkRefNum ) ;
if ( ! error && forkRefNum )
error = FSWriteFork ( forkRefNum , fsFromStart , 0 , [ [ resource data ] length ] , [ [ resource data ] bytes ] , NULL ) ;
if ( forkRefNum ) FSClose ( forkRefNum ) ;
}
DisposePtr ( ( Ptr ) fileRef ) ;
return YES ;
}
/ * !
@ method writeResourceMap :
@ abstract Writes all resources ( except the ones representing other forks of the file ) to the specified resource file .
* /
- ( BOOL ) writeResourceMap : ( SInt16 ) fileRefNum
{
// make the resource file current
OSStatus error = noErr ;
SInt16 oldResFile = CurResFile ( ) ;
UseResFile ( fileRefNum ) ;
// loop over all our resources
Resource * resource ;
NSEnumerator * enumerator = [ resources objectEnumerator ] ;
while ( resource = [ enumerator nextObject ] )
{
Str255 nameStr ;
char resType [ 5 ] ; // includes null char for getCString :
short resIDShort ;
short attrsShort ;
Handle resourceHandle ;
// if the 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 ] ) ;
// convert unicode name to pascal string
nameStr [ 0 ] = [ [ resource name ] lengthOfBytesUsingEncoding : NSMacOSRomanStringEncoding ] ;
BlockMoveData ( [ [ resource name ] cStringUsingEncoding : NSMacOSRomanStringEncoding ] , & nameStr [ 1 ] , nameStr [ 0 ] ) ;
// convert type string to ResType
[ [ resource type ] getCString : resType maxLength : 4 ] ;
// convert NSData to resource handle
HLockHi ( resourceHandle ) ;
[ [ resource data ] getBytes : * resourceHandle ] ;
HUnlock ( resourceHandle ) ;
// now that everything ' s converted , tell the resource manager we want to create this resource
AddResource ( resourceHandle , * ( ResType * ) resType , resIDShort , nameStr ) ;
if ( ResError ( ) = = addResFailed )
{
NSLog ( @ "*Saving failed*; could not add resource ID %@ of type %@ to file." , [ resource resID ] , [ resource type ] ) ;
DisposeHandle ( resourceHandle ) ;
error = addResFailed ;
}
else
{
// NSLog ( @ "Added resource ID %@ of type %@ to file." , [ resource resID ] , [ resource type ] ) ;
SetResAttrs ( resourceHandle , attrsShort ) ;
ChangedResource ( resourceHandle ) ;
// the resourceHandle memory is disposed of when calling CloseResFile ( ) for the file to which the resource has been added
}
}
// update the file on disk
UpdateResFile ( fileRefNum ) ;
// restore original resource file
UseResFile ( oldResFile ) ;
return error ? NO : YES ;
}
- ( void ) setTypeCreatorAfterSave : ( id ) userInfo
{
FInfo finderInfo ;
FSRef * fileRef = ( FSRef * ) NewPtrClear ( sizeof ( FSRef ) ) ;
FSSpec * fileSpec = ( FSSpec * ) NewPtrClear ( sizeof ( FSSpec ) ) ;
OSStatus error = FSPathMakeRef ( ( const UInt8 * ) [ [ self fileName ] UTF8String ] , fileRef , nil ) ;
if ( ! error )
{
error = FSGetCatalogInfo ( fileRef , kFSCatInfoNone , NULL , NULL , fileSpec , NULL ) ;
if ( ! error )
{
error = FSpGetFInfo ( fileSpec , & finderInfo ) ;
if ( ! error )
{
[ [ self type ] getBytes : & finderInfo . fdType length : 4 ] ;
[ [ self creator ] getBytes : & finderInfo . fdCreator length : 4 ] ;
// NSLog ( @ "setting finder info to type: %X; creator: %X" , finderInfo . fdType , finderInfo . fdCreator ) ;
error = FSpSetFInfo ( fileSpec , & finderInfo ) ;
FSpGetFInfo ( fileSpec , & finderInfo ) ;
// NSLog ( @ "finder info got set to type: %X; creator: %X" , finderInfo . fdType , finderInfo . fdCreator ) ;
}
else NSLog ( @ "error getting Finder info. (error=%d, spec=%d, ref=%d)" , error , fileSpec , fileRef ) ;
}
else NSLog ( @ "error converting fsref to fsspec. (error=%d, spec=%d, ref=%d)" , error , fileSpec , fileRef ) ;
}
else NSLog ( @ "error making fsref from file path. (error=%d, ref=%d, path=%@)" , error , fileRef , [ self fileName ] ) ;
}
# pragma mark -
# pragma mark Export to File
/ * !
@ method exportResources :
@ author Nicholas Shanks
@ created 24 October 2003
@ pending note that this method will cause a cascade of sheets to be displayed for each resource being exported ! v . bad needs fixing
* /
- ( IBAction ) exportResources : ( id ) sender
{
if ( [ outlineView numberOfSelectedRows ] > 1 )
{
NSOpenPanel * panel = [ NSOpenPanel openPanel ] ;
[ panel setAllowsMultipleSelection : NO ] ;
[ panel setCanChooseDirectories : YES ] ;
[ panel setCanChooseFiles : NO ] ;
[ panel beginSheetForDirectory : nil file : nil modalForWindow : mainWindow modalDelegate : self didEndSelector : @ selector ( folderChoosePanelDidEnd : returnCode : contextInfo : ) contextInfo : nil ] ;
}
else
{
[ self exportResource : [ outlineView selectedItem ] ] ;
}
}
/ * !
@ method exportResource :
@ author Uli Kusterer
@ updated 2003 -10 -24 NGS : moved IBAction target to exportResources : above , renamed this method
* /
# warning Note to Uli : how about changing the selector that the plug should implement to - ( BOOL ) dataForFileExport : ( NSData * * ) fileData ofType : ( NSString * * ) fileType . This is basically a concatenation of the two methods you came up with , but can allow the host app to specify a preferred file type ( e . g . EPS ) to a plug ( say the PICT plug ) and if the plug can ' t return data in that format , that ' s OK , it just returns the fileType of the associated data anyway . I would also recommend adding a plug method called something like availableTypesForFileExport : which returns a dictionary of file extensions and human - readable names ( names should be overridden by system default names for that extension if present ) that the plug can export data into , useful for say populating a pop - up menu in the export dialog .
- ( void ) exportResource : ( Resource * ) resource
{
Class editorClass = [ [ RKEditorRegistry defaultRegistry ] editorForType : [ resource type ] ] ;
NSData * exportData = [ resource data ] ;
NSString * extension = [ [ [ resource type ] lowercaseString ] stringByTrimmingCharactersInSet : [ NSCharacterSet whitespaceAndNewlineCharacterSet ] ] ;
// basic overrides for file name extensions ( assume no plug - ins installed )
NSString * newExtension ;
NSDictionary * adjustments = [ NSDictionary dictionaryWithObjectsAndKeys : @ "ttf" , @ "sfnt" , nil ] ;
if ( newExtension = [ adjustments valueForKey : extension ] )
extension = newExtension ;
// ask for data
if ( [ editorClass respondsToSelector : @ selector ( dataForFileExport : ) ] )
exportData = [ editorClass dataForFileExport : resource ] ;
// ask for file extension
if ( [ editorClass respondsToSelector : @ selector ( filenameExtensionForFileExport : ) ] )
extension = [ editorClass filenameExtensionForFileExport : resource ] ;
NSSavePanel * panel = [ NSSavePanel savePanel ] ;
NSString * filename = [ resource name ] ? [ resource name ] : NSLocalizedString ( @ "Untitled Resource" , nil ) ;
filename = [ filename stringByAppendingFormat : @ ".%@" , extension ] ;
[ panel beginSheetForDirectory : nil file : filename modalForWindow : mainWindow modalDelegate : self didEndSelector : @ selector ( exportPanelDidEnd : returnCode : contextInfo : ) contextInfo : [ exportData retain ] ] ;
}
- ( void ) exportPanelDidEnd : ( NSSavePanel * ) sheet returnCode : ( int ) returnCode contextInfo : ( void * ) contextInfo
{
NSData * data = ( NSData * ) contextInfo ;
[ data autorelease ] ;
if ( returnCode = = NSOKButton )
[ data writeToFile : [ sheet filename ] atomically : YES ] ;
}
- ( void ) folderChoosePanelDidEnd : ( NSSavePanel * ) sheet returnCode : ( int ) returnCode contextInfo : ( void * ) contextInfo
{
if ( returnCode = = NSOKButton )
{
NSUInteger i = 1 ;
Resource * resource ;
NSString * path , * filename , * extension ;
NSDictionary * adjustments = [ NSDictionary dictionaryWithObjectsAndKeys : @ "ttf" , @ "sfnt" , @ "png" , @ "PNGf" , nil ] ;
NSEnumerator * enumerator = [ [ outlineView selectedItems ] objectEnumerator ] ;
while ( resource = [ enumerator nextObject ] )
{
Class editorClass = [ [ RKEditorRegistry defaultRegistry ] editorForType : [ resource type ] ] ;
NSData * exportData = [ resource data ] ;
extension = [ [ [ resource type ] lowercaseString ] stringByTrimmingCharactersInSet : [ NSCharacterSet whitespaceAndNewlineCharacterSet ] ] ;
// basic overrides for file name extensions ( assume no plug - ins installed )
if ( [ adjustments objectForKey : [ resource type ] ] )
extension = [ adjustments objectForKey : [ resource type ] ] ;
// ask for data
if ( [ editorClass respondsToSelector : @ selector ( dataForFileExport : ) ] )
exportData = [ editorClass dataForFileExport : resource ] ;
// ask for file extension
if ( [ editorClass respondsToSelector : @ selector ( filenameExtensionForFileExport : ) ] )
extension = [ editorClass filenameExtensionForFileExport : resource ] ;
filename = [ resource name ] ;
if ( ! filename || [ filename isEqualToString : @ "" ] )
{
filename = [ NSString stringWithFormat : NSLocalizedString ( @ "Untitled '%@' Resource %d" , nil ) , [ resource type ] , i + + ] ;
filename = [ filename stringByAppendingPathExtension : extension ] ;
}
else
{
NSUInteger j = 1 ;
NSString * tempname = [ filename stringByAppendingPathExtension : extension ] ;
while ( [ [ NSFileManager defaultManager ] fileExistsAtPath : tempname ] )
{
tempname = [ filename stringByAppendingFormat : @ " (%d)" , j + + ] ;
tempname = [ tempname stringByAppendingPathExtension : extension ] ;
}
filename = tempname ;
}
path = [ [ sheet filename ] stringByAppendingPathComponent : filename ] ;
[ exportData writeToFile : path atomically : YES ] ;
}
}
}
# pragma mark -
# pragma mark Window Management
2002-02-06 20:57:56 +00:00
2001-10-19 19:41:13 +00:00
- ( NSString * ) windowNibName
{
return @ "ResourceDocument" ;
}
2002-02-23 03:40:24 +00:00
/ * This is not used , just here for reference in case I need it in the future
- ( void ) makeWindowControllers
{
ResourceWindowController * resourceController = [ [ ResourceWindowController allocWithZone : [ self zone ] ] initWithWindowNibName : @ "ResourceDocument" ] ;
[ self addWindowController : resourceController ] ;
} * /
2002-02-02 11:31:28 +00:00
- ( void ) windowControllerDidLoadNib : ( NSWindowController * ) controller
2001-10-19 19:41:13 +00:00
{
2002-02-07 03:45:43 +00:00
[ super windowControllerDidLoadNib : controller ] ;
2002-02-06 20:57:56 +00:00
[ self setupToolbar : controller ] ;
2002-02-07 03:45:43 +00:00
{ // set up first column in outline view to display images as well as text
ResourceNameCell * resourceNameCell = [ [ [ ResourceNameCell alloc ] init ] autorelease ] ;
[ resourceNameCell setEditable : YES ] ;
[ [ outlineView tableColumnWithIdentifier : @ "name" ] setDataCell : resourceNameCell ] ;
2008-07-31 20:27:55 +00:00
// NSLog ( @ "Changed data cell" ) ;
2002-02-07 03:45:43 +00:00
}
2008-07-31 20:27:55 +00:00
// set outline view ' s inter - cell spacing to zero to avoid getting gaps between blue bits
2002-05-31 00:17:53 +00:00
[ outlineView setIntercellSpacing : NSMakeSize ( 0 , 0 ) ] ;
2002-11-15 15:12:42 +00:00
[ outlineView setTarget : self ] ;
[ outlineView setDoubleAction : @ selector ( openResources : ) ] ;
2008-07-31 20:27:55 +00:00
[ outlineView setVerticalMotionCanBeginDrag : YES ] ;
[ outlineView registerForDraggedTypes : [ NSArray arrayWithObjects : RKResourcePboardType , NSStringPboardType , NSFilenamesPboardType , nil ] ] ;
2002-05-31 00:17:53 +00:00
2002-02-14 23:24:53 +00:00
// register for resource will change notifications ( for undo management )
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceNameWillChange : ) name : ResourceNameWillChangeNotification object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceIDWillChange : ) name : ResourceIDWillChangeNotification object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceTypeWillChange : ) name : ResourceTypeWillChangeNotification object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceAttributesWillChange : ) name : ResourceAttributesWillChangeNotification object : nil ] ;
2002-02-11 01:22:17 +00:00
// [ [ controller window ] setResizeIncrements : NSMakeSize ( 1 , 18 ) ] ;
2001-10-19 19:41:13 +00:00
[ dataSource setResources : resources ] ;
}
2002-02-15 01:52:23 +00:00
- ( void ) printShowingPrintPanel : ( BOOL ) flag
{
2002-02-23 03:40:24 +00:00
NSPrintOperation * printOperation = [ NSPrintOperation printOperationWithView : [ mainWindow contentView ] ] ;
[ printOperation runOperationModalForWindow : mainWindow delegate : self didRunSelector : @ selector ( printOperationDidRun : success : contextInfo : ) contextInfo : nil ] ;
2002-02-15 01:52:23 +00:00
}
- ( void ) printOperationDidRun : ( NSPrintOperation * ) printOperation success : ( BOOL ) success contextInfo : ( void * ) contextInfo
{
2008-07-31 20:27:55 +00:00
if ( ! success ) NSLog ( @ "Printing Failed!" ) ;
2002-02-15 01:52:23 +00:00
}
2001-10-19 19:41:13 +00:00
- ( BOOL ) keepBackupFile
{
2002-02-07 03:45:43 +00:00
return [ [ NSUserDefaults standardUserDefaults ] boolForKey : @ "PreserveBackups" ] ;
2001-10-19 19:41:13 +00:00
}
2002-02-14 23:24:53 +00:00
- ( BOOL ) validateMenuItem : ( NSMenuItem * ) item
{
2002-02-15 01:52:23 +00:00
int selectedRows = [ outlineView numberOfSelectedRows ] ;
2002-02-23 03:40:24 +00:00
Resource * resource = ( Resource * ) [ outlineView selectedItem ] ;
2002-02-15 01:52:23 +00:00
// file menu
2008-07-31 20:27:55 +00:00
if ( [ item action ] = = @ selector ( saveDocument : ) ) return [ self isDocumentEdited ] ;
2002-02-15 01:52:23 +00:00
// edit menu
2008-07-31 20:27:55 +00:00
else if ( [ item action ] = = @ selector ( clear : ) ) return selectedRows > 0 ;
else if ( [ item action ] = = @ selector ( selectAll : ) ) return [ outlineView numberOfRows ] > 0 ;
else if ( [ item action ] = = @ selector ( deselectAll : ) ) return selectedRows > 0 ;
2002-02-15 01:52:23 +00:00
// resource menu
2008-07-31 20:27:55 +00:00
else if ( [ item action ] = = @ selector ( openResources : ) ) return selectedRows > 0 ;
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 : ) )
2003-08-01 22:23:50 +00:00
{
2008-07-31 20:27:55 +00:00
if ( selectedRows < 1 ) return NO ;
Class editorClass = [ [ RKEditorRegistry defaultRegistry ] editorForType : [ resource type ] ] ;
return [ editorClass respondsToSelector : @ selector ( imageForImageFileExport : ) ] ;
2003-08-01 22:23:50 +00:00
}
2008-07-31 20:27:55 +00:00
else if ( [ item action ] = = @ selector ( playSound : ) ) return selectedRows = = 1 && [ [ resource type ] isEqualToString : @ "snd " ] ;
else if ( [ item action ] = = @ selector ( revertResourceToSaved : ) ) return selectedRows = = 1 && [ resource isDirty ] ;
2002-02-14 23:24:53 +00:00
else return [ super validateMenuItem : item ] ;
}
2002-02-07 03:45:43 +00:00
# pragma mark -
2008-07-31 20:27:55 +00:00
# pragma mark Toolbar Management
2002-02-06 20:57:56 +00:00
2002-02-11 01:22:17 +00:00
static NSString * RKToolbarIdentifier = @ "com.nickshanks.resknife.toolbar" ;
static NSString * RKCreateItemIdentifier = @ "com.nickshanks.resknife.toolbar.create" ;
static NSString * RKDeleteItemIdentifier = @ "com.nickshanks.resknife.toolbar.delete" ;
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" ;
2008-07-31 20:27:55 +00:00
static NSString * RKExportItemIdentifier = @ "com.nickshanks.resknife.toolbar.export" ;
2002-02-06 20:57:56 +00:00
2002-02-23 03:40:24 +00:00
- ( void ) setupToolbar : ( NSWindowController * ) windowController
2002-02-06 20:57:56 +00:00
{
/ * This routine should become invalid once toolbars are integrated into nib files * /
2002-04-30 23:44:23 +00:00
NSToolbarItem * item ;
[ toolbarItems removeAllObjects ] ; // just in case this method is called more than once per document ( which it shouldn ' t be ! )
item = [ [ NSToolbarItem alloc ] initWithItemIdentifier : RKCreateItemIdentifier ] ;
2003-08-01 22:23:50 +00:00
[ item autorelease ] ;
2002-04-30 23:44:23 +00:00
[ item setLabel : NSLocalizedString ( @ "Create" , nil ) ] ;
[ item setPaletteLabel : NSLocalizedString ( @ "Create" , nil ) ] ;
[ item setToolTip : NSLocalizedString ( @ "Create New Resource" , nil ) ] ;
[ item setImage : [ NSImage imageNamed : @ "Create" ] ] ;
[ item setTarget : self ] ;
[ item setAction : @ selector ( showCreateResourceSheet : ) ] ;
[ toolbarItems setObject : item forKey : RKCreateItemIdentifier ] ;
item = [ [ NSToolbarItem alloc ] initWithItemIdentifier : RKDeleteItemIdentifier ] ;
2003-08-01 22:23:50 +00:00
[ item autorelease ] ;
2002-04-30 23:44:23 +00:00
[ item setLabel : NSLocalizedString ( @ "Delete" , nil ) ] ;
[ item setPaletteLabel : NSLocalizedString ( @ "Delete" , nil ) ] ;
[ item setToolTip : NSLocalizedString ( @ "Delete Selected Resource" , nil ) ] ;
[ item setImage : [ NSImage imageNamed : @ "Delete" ] ] ;
[ item setTarget : self ] ;
[ item setAction : @ selector ( clear : ) ] ;
[ toolbarItems setObject : item forKey : RKDeleteItemIdentifier ] ;
2008-07-31 20:27:55 +00:00
NSImage * image ;
2002-04-30 23:44:23 +00:00
item = [ [ NSToolbarItem alloc ] initWithItemIdentifier : RKEditItemIdentifier ] ;
2003-08-01 22:23:50 +00:00
[ item autorelease ] ;
2002-04-30 23:44:23 +00:00
[ item setLabel : NSLocalizedString ( @ "Edit" , nil ) ] ;
[ item setPaletteLabel : NSLocalizedString ( @ "Edit" , nil ) ] ;
[ item setToolTip : NSLocalizedString ( @ "Edit Resource In Default Editor" , nil ) ] ;
2008-07-31 20:27:55 +00:00
if ( image = [ [ NSWorkspace sharedWorkspace ] iconForFileType : @ "rtf" ] )
[ item setImage : image ] ;
else [ item setImage : [ NSImage imageNamed : @ "Edit" ] ] ;
2002-04-30 23:44:23 +00:00
[ item setTarget : self ] ;
[ item setAction : @ selector ( openResources : ) ] ;
[ toolbarItems setObject : item forKey : RKEditItemIdentifier ] ;
item = [ [ NSToolbarItem alloc ] initWithItemIdentifier : RKEditHexItemIdentifier ] ;
2003-08-01 22:23:50 +00:00
[ item autorelease ] ;
2002-04-30 23:44:23 +00:00
[ item setLabel : NSLocalizedString ( @ "Edit Hex" , nil ) ] ;
[ item setPaletteLabel : NSLocalizedString ( @ "Edit Hex" , nil ) ] ;
[ item setToolTip : NSLocalizedString ( @ "Edit Resource As Hexadecimal" , nil ) ] ;
2008-07-31 20:27:55 +00:00
if ( image = [ [ NSWorkspace sharedWorkspace ] iconForFileType : @ "txt" ] )
[ item setImage : image ] ;
else [ item setImage : [ NSImage imageNamed : @ "Edit Hex" ] ] ;
2002-04-30 23:44:23 +00:00
[ item setTarget : self ] ;
[ item setAction : @ selector ( openResourcesAsHex : ) ] ;
[ toolbarItems setObject : item forKey : RKEditHexItemIdentifier ] ;
item = [ [ NSToolbarItem alloc ] initWithItemIdentifier : RKSaveItemIdentifier ] ;
2003-08-01 22:23:50 +00:00
[ item autorelease ] ;
2002-04-30 23:44:23 +00:00
[ 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 ) ] ] ;
[ item setImage : [ NSImage imageNamed : @ "Save" ] ] ;
[ item setTarget : self ] ;
[ item setAction : @ selector ( saveDocument : ) ] ;
[ toolbarItems setObject : item forKey : RKSaveItemIdentifier ] ;
item = [ [ NSToolbarItem alloc ] initWithItemIdentifier : RKShowInfoItemIdentifier ] ;
2003-08-01 22:23:50 +00:00
[ item autorelease ] ;
2002-04-30 23:44:23 +00:00
[ item setLabel : NSLocalizedString ( @ "Show Info" , nil ) ] ;
[ item setPaletteLabel : NSLocalizedString ( @ "Show Info" , nil ) ] ;
[ item setToolTip : NSLocalizedString ( @ "Show Resource Information Window" , nil ) ] ;
2008-07-31 20:27:55 +00:00
if ( image = [ NSImage imageNamed : @ "NSGetInfoToolbar" ] )
[ item setImage : image ] ;
else [ item setImage : [ NSImage imageNamed : @ "Show Info" ] ] ;
2002-04-30 23:44:23 +00:00
[ item setTarget : [ NSApp delegate ] ] ;
[ item setAction : @ selector ( showInfo : ) ] ;
[ toolbarItems setObject : item forKey : RKShowInfoItemIdentifier ] ;
2003-08-01 22:23:50 +00:00
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 ] ;
2008-07-31 20:27:55 +00:00
[ item setAction : @ selector ( exportResources : ) ] ;
2003-08-01 22:23:50 +00:00
[ toolbarItems setObject : item forKey : RKExportItemIdentifier ] ;
2002-04-30 23:44:23 +00:00
2008-07-31 20:27:55 +00:00
if ( [ windowController window ] = = mainWindow )
2002-02-23 03:40:24 +00:00
{
NSToolbar * toolbar = [ [ [ NSToolbar alloc ] initWithIdentifier : RKToolbarIdentifier ] autorelease ] ;
// set toolbar properties
2003-08-01 22:23:50 +00:00
[ toolbar setVisible : YES ] ;
2002-02-23 03:40:24 +00:00
[ toolbar setAutosavesConfiguration : YES ] ;
[ toolbar setAllowsUserCustomization : YES ] ;
[ toolbar setDisplayMode : NSToolbarDisplayModeDefault ] ;
2002-04-30 23:44:23 +00:00
// attach toolbar to window
2002-02-23 03:40:24 +00:00
[ toolbar setDelegate : self ] ;
[ mainWindow setToolbar : toolbar ] ;
2008-07-31 20:27:55 +00:00
}
2002-02-06 20:57:56 +00:00
}
- ( NSToolbarItem * ) toolbar : ( NSToolbar * ) toolbar itemForItemIdentifier : ( NSString * ) itemIdentifier willBeInsertedIntoToolbar : ( BOOL ) flag
{
2002-04-30 23:44:23 +00:00
return [ toolbarItems objectForKey : itemIdentifier ] ;
2002-02-06 20:57:56 +00:00
}
- ( NSArray * ) toolbarDefaultItemIdentifiers : ( NSToolbar * ) toolbar
{
2003-08-01 22:23:50 +00:00
return [ NSArray arrayWithObjects : RKCreateItemIdentifier , RKShowInfoItemIdentifier , RKDeleteItemIdentifier , NSToolbarSeparatorItemIdentifier , RKEditItemIdentifier , RKEditHexItemIdentifier , NSToolbarSeparatorItemIdentifier , RKSaveItemIdentifier , NSToolbarPrintItemIdentifier , NSToolbarFlexibleSpaceItemIdentifier , NSToolbarCustomizeToolbarItemIdentifier , nil ] ;
2002-02-06 20:57:56 +00:00
}
- ( NSArray * ) toolbarAllowedItemIdentifiers : ( NSToolbar * ) toolbar
{
2003-08-01 22:23:50 +00:00
return [ NSArray arrayWithObjects : RKCreateItemIdentifier , RKDeleteItemIdentifier , RKEditItemIdentifier , RKEditHexItemIdentifier , RKSaveItemIdentifier , RKExportItemIdentifier , RKShowInfoItemIdentifier , NSToolbarPrintItemIdentifier , NSToolbarCustomizeToolbarItemIdentifier , NSToolbarFlexibleSpaceItemIdentifier , NSToolbarSpaceItemIdentifier , NSToolbarSeparatorItemIdentifier , nil ] ;
2002-02-06 20:57:56 +00:00
}
2002-02-07 03:45:43 +00:00
- ( BOOL ) validateToolbarItem : ( NSToolbarItem * ) item
{
BOOL valid = NO ;
2002-02-23 03:40:24 +00:00
int selectedRows = [ outlineView numberOfSelectedRows ] ;
2002-02-07 03:45:43 +00:00
NSString * identifier = [ item itemIdentifier ] ;
2008-07-31 20:27:55 +00:00
if ( [ identifier isEqualToString : RKCreateItemIdentifier ] ) valid = YES ;
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 ;
2002-02-07 03:45:43 +00:00
return valid ;
}
# pragma mark -
2008-07-31 20:27:55 +00:00
# pragma mark Document Management
2002-02-07 03:45:43 +00:00
- ( IBAction ) showCreateResourceSheet : ( id ) sender
{
2002-02-23 03:40:24 +00:00
// bug : ResourceDocument allocs a sheet controller , but it ' s never disposed of
CreateResourceSheetController * sheetController = [ [ CreateResourceSheetController alloc ] initWithWindowNibName : @ "CreateResourceSheet" ] ;
[ sheetController showCreateResourceSheet : self ] ;
2002-02-07 03:45:43 +00:00
}
2002-02-11 01:22:17 +00:00
2008-07-31 20:27:55 +00:00
/ * - ( IBAction ) showSelectTemplateSheet : ( id ) sender
2002-04-27 18:17:47 +00:00
{
// bug : ResourceDocument allocs a sheet controller , but it ' s never disposed of
// SelectTemplateSheetController * sheetController = [ [ CreateResourceSheetController alloc ] initWithWindowNibName : @ "SelectTemplateSheet" ] ;
// [ sheetController showSelectTemplateSheet : self ] ;
2008-07-31 20:27:55 +00:00
} * /
2002-04-27 18:17:47 +00:00
2002-03-31 12:00:02 +00:00
- ( IBAction ) openResources : ( id ) sender
2002-02-07 03:45:43 +00:00
{
2008-07-31 20:27:55 +00:00
// ignore double - clicks in table header
if ( sender = = outlineView && [ outlineView clickedRow ] = = -1 )
return ;
2002-03-31 12:00:02 +00:00
Resource * resource ;
NSArray * selected = [ outlineView selectedItems ] ;
NSEnumerator * enumerator = [ selected objectEnumerator ] ;
2008-07-31 20:27:55 +00:00
while ( resource = [ enumerator nextObject ] )
2002-03-31 12:00:02 +00:00
[ self openResourceUsingEditor : resource ] ;
2002-02-23 03:40:24 +00:00
}
2002-03-31 12:00:02 +00:00
- ( IBAction ) openResourcesInTemplate : ( id ) sender
2002-02-23 03:40:24 +00:00
{
2002-03-31 12:00:02 +00:00
// opens the resource in its default template
Resource * resource ;
NSArray * selected = [ outlineView selectedItems ] ;
NSEnumerator * enumerator = [ selected objectEnumerator ] ;
2008-07-31 20:27:55 +00:00
while ( resource = [ enumerator nextObject ] )
2002-03-31 12:00:02 +00:00
[ self openResource : resource usingTemplate : [ resource type ] ] ;
}
- ( IBAction ) openResourcesAsHex : ( id ) sender
{
Resource * resource ;
NSArray * selected = [ outlineView selectedItems ] ;
NSEnumerator * enumerator = [ selected objectEnumerator ] ;
2008-07-31 20:27:55 +00:00
while ( resource = [ enumerator nextObject ] )
2002-03-31 12:00:02 +00:00
[ self openResourceAsHex : resource ] ;
2002-02-23 03:40:24 +00:00
}
2003-08-01 22:23:50 +00:00
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
2008-07-31 20:27:55 +00:00
/ * Method name should be changed to : - ( void ) openResource : ( Resource * ) resource usingEditor : ( Class ) overrideEditor < nil = = default editor > * /
- ( void ) openResourceUsingEditor : ( Resource * ) resource
2002-03-31 12:00:02 +00:00
{
2008-07-31 20:27:55 +00:00
Class editorClass = [ [ RKEditorRegistry defaultRegistry ] editorForType : [ resource type ] ] ;
2002-04-04 16:57:07 +00:00
// open the resources , passing in the template to use
2008-07-31 20:27:55 +00:00
if ( editorClass )
2002-04-04 16:57:07 +00:00
{
// 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 ?
2008-07-31 20:27:55 +00:00
// update : doug says window controllers automatically release themselves when their window is closed . All default plugs have a window controller as their principal class , but 3 rd party ones might not
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceDataDidChange : ) name : ResourceDataDidChangeNotification object : resource ] ;
2003-08-01 22:23:50 +00:00
id plug = [ ( id < ResKnifePluginProtocol > ) [ editorClass alloc ] initWithResource : resource ] ;
2008-07-31 20:27:55 +00:00
if ( plug ) return ;
2002-04-04 16:57:07 +00:00
}
2002-04-27 18:17:47 +00:00
2002-04-04 16:57:07 +00:00
// if no editor exists , or the editor is broken , open using template
2002-04-27 18:17:47 +00:00
[ self openResource : resource usingTemplate : [ resource type ] ] ;
2002-03-31 12:00:02 +00:00
}
2003-08-01 22:23:50 +00:00
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
2008-07-31 20:27:55 +00:00
- ( void ) openResource : ( Resource * ) resource usingTemplate : ( NSString * ) templateName
2002-02-23 03:40:24 +00:00
{
// opens resource in template using TMPL resource with name templateName
2008-07-31 20:27:55 +00:00
Class editorClass = [ [ RKEditorRegistry defaultRegistry ] editorForType : @ "Template Editor" ] ;
2002-03-31 12:00:02 +00:00
2003-08-01 22:23:50 +00:00
// 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 !
2002-04-29 00:05:34 +00:00
Resource * tmpl = [ Resource resourceOfType : @ "TMPL" withName : [ resource type ] inDocument : nil ] ;
2002-02-23 03:40:24 +00:00
2002-03-31 12:00:02 +00:00
// open the resources , passing in the template to use
2008-07-31 20:27:55 +00:00
if ( tmpl && editorClass )
2002-02-23 03:40:24 +00:00
{
2008-07-31 20:27:55 +00:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceDataDidChange : ) name : ResourceDataDidChangeNotification object : resource ] ;
id plug = [ ( id < ResKnifeTemplatePluginProtocol > ) [ editorClass alloc ] initWithResources : resource , tmpl , nil ] ;
if ( plug ) return ;
2002-02-23 03:40:24 +00:00
}
2002-04-27 18:17:47 +00:00
2002-02-23 03:40:24 +00:00
// if no template exists , or template editor is broken , open as hex
2002-04-27 18:17:47 +00:00
[ self openResourceAsHex : resource ] ;
2002-02-07 03:45:43 +00:00
}
2002-02-11 01:22:17 +00:00
2008-07-31 20:27:55 +00:00
/ * !
@ method openResourceAsHex :
@ author Nicholas Shanks
@ created 2001
@ updated 2003 -07 -31 UK : Changed to use plugin registry instead of file name .
@ description 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 .
@ param resource Resource to edit
* /
2003-08-01 22:23:50 +00:00
2008-07-31 20:27:55 +00:00
- ( void ) openResourceAsHex : ( Resource * ) resource
2002-02-07 03:45:43 +00:00
{
2008-07-31 20:27:55 +00:00
Class editorClass = [ [ RKEditorRegistry defaultRegistry ] editorForType : @ "Hexadecimal Editor" ] ;
2002-03-31 12:00:02 +00:00
// 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 ?
2003-08-01 22:23:50 +00:00
// update : doug says window controllers automatically release themselves when their window is closed .
2008-07-31 20:27:55 +00:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceDataDidChange : ) name : ResourceDataDidChangeNotification object : resource ] ;
2003-08-01 22:23:50 +00:00
NSWindowController * plugController = [ ( id < ResKnifePluginProtocol > ) [ editorClass alloc ] initWithResource : resource ] ;
2008-07-31 20:27:55 +00:00
# pragma unused ( plugController )
2002-02-07 03:45:43 +00:00
}
2002-02-11 01:22:17 +00:00
2008-07-31 20:27:55 +00:00
/ * !
@ method playSound :
@ abstract Plays the selected carbon ' snd ' resource .
@ author Nicholas Shanks
@ created 2001
@ updated 2003 -10 -22 NGS : Moved playing into seperate thread to avoid locking up main thread .
@ pending 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 .
@ description This method is called from a menu item which is validated against there being only one selected resource ( of type ' snd ' ) , so shouldn ' t have to deal with playing multiple sounds , though this may of course change in future .
@ param sender ignored
* /
2003-08-01 22:23:50 +00:00
2002-02-07 03:45:43 +00:00
- ( IBAction ) playSound : ( id ) sender
{
2002-10-04 19:54:05 +00:00
// bug : can only cope with one selected item
NSData * data = [ ( Resource * ) [ outlineView itemAtRow : [ outlineView selectedRow ] ] data ] ;
2008-07-31 20:27:55 +00:00
if ( data && [ data length ] ! = 0 )
{
[ NSThread detachNewThreadSelector : @ selector ( playSoundThreadController : ) toTarget : self withObject : data ] ;
}
else NSBeep ( ) ;
}
/ * !
@ method playSoundThreadController :
@ abstract Plays a carbon ' snd ' resource .
@ author Nicholas Shanks
@ created 2003 -10 -22
@ pending 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 .
@ description This method was added to prevent having to use AsynchSoundHelper to play them asynchronously in the main thread and all the associated idle checking , which since we have no event loop , would have to have been called from a timer . I ' m not sure if the autorelease pool is necessary , as no cocoa objects are created , but an NSData is passed in and messages sent to it , and NSBeep ( ) might need one .
@ param data An NSData object containing the snd resource data to be played .
* /
- ( void ) playSoundThreadController : ( NSData * ) data
{
NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ] ;
if ( data && [ data length ] ! = 0 )
2002-10-04 19:54:05 +00:00
{
2008-07-31 20:27:55 +00:00
// plays sound synchronously , thread exits when sound is done playing
2002-10-04 19:54:05 +00:00
SndListPtr sndPtr = ( SndListPtr ) [ data bytes ] ;
2008-07-31 20:27:55 +00:00
SndPlay ( nil , & sndPtr , false ) ;
2002-10-04 19:54:05 +00:00
}
else NSBeep ( ) ;
2008-07-31 20:27:55 +00:00
[ pool release ] ;
2002-02-12 04:01:47 +00:00
}
2008-07-31 20:27:55 +00:00
/ * !
@ method sound : didFinishPlaying :
@ abstract Called frequently when playing a sound via NSSound . Unused , here for reference and possible future use .
@ author Nicholas Shanks
@ pending 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 .
@ param sound The NSSound that is playing .
@ param finished Flag to indicate if it has just finished and that we should clean up .
* /
2002-02-12 04:01:47 +00:00
- ( void ) sound : ( NSSound * ) sound didFinishPlaying : ( BOOL ) finished
{
2008-07-31 20:27:55 +00:00
// unused because I can ' t get NSSound to play snd resources , so I use Carbon ' s SndPlay ( ) , above
if ( finished ) [ sound release ] ;
NSLog ( @ "sound released" ) ;
2002-02-07 03:45:43 +00:00
}
2002-02-11 01:22:17 +00:00
2002-02-14 23:24:53 +00:00
- ( void ) resourceNameWillChange : ( NSNotification * ) notification
{
// this saves the current resource ' s name so we can undo the change
Resource * resource = ( Resource * ) [ notification object ] ;
[ [ self undoManager ] registerUndoWithTarget : resource selector : @ selector ( setName : ) object : [ [ [ resource name ] copy ] autorelease ] ] ;
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "Name Change" , nil ) ] ;
}
- ( void ) resourceIDWillChange : ( NSNotification * ) notification
{
// this saves the current resource ' s ID number so we can undo the change
Resource * resource = ( Resource * ) [ notification object ] ;
[ [ self undoManager ] registerUndoWithTarget : resource selector : @ selector ( setResID : ) object : [ [ [ resource resID ] copy ] autorelease ] ] ;
2008-07-31 20:27:55 +00:00
if ( [ [ resource name ] length ] = = 0 )
2002-02-14 23:24:53 +00:00
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "ID Change" , nil ) ] ;
2008-07-31 20:27:55 +00:00
else [ [ self undoManager ] setActionName : [ NSString stringWithFormat : NSLocalizedString ( @ "ID Change for '%@'" , nil ) , [ resource name ] ] ] ;
2002-02-14 23:24:53 +00:00
}
- ( void ) resourceTypeWillChange : ( NSNotification * ) notification
{
// this saves the current resource ' s type so we can undo the change
Resource * resource = ( Resource * ) [ notification object ] ;
[ [ self undoManager ] registerUndoWithTarget : resource selector : @ selector ( setType : ) object : [ [ [ resource type ] copy ] autorelease ] ] ;
2008-07-31 20:27:55 +00:00
if ( [ [ resource name ] length ] = = 0 )
2002-02-14 23:24:53 +00:00
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "Type Change" , nil ) ] ;
2008-07-31 20:27:55 +00:00
else [ [ self undoManager ] setActionName : [ NSString stringWithFormat : NSLocalizedString ( @ "Type Change for '%@'" , nil ) , [ resource name ] ] ] ;
2002-02-14 23:24:53 +00:00
}
- ( void ) resourceAttributesWillChange : ( NSNotification * ) notification
{
// this saves the current state of the resource ' s attributes so we can undo the change
Resource * resource = ( Resource * ) [ notification object ] ;
[ [ self undoManager ] registerUndoWithTarget : resource selector : @ selector ( setAttributes : ) object : [ [ [ resource attributes ] copy ] autorelease ] ] ;
2008-07-31 20:27:55 +00:00
if ( [ [ resource name ] length ] = = 0 )
2002-02-14 23:24:53 +00:00
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "Attributes Change" , nil ) ] ;
2008-07-31 20:27:55 +00:00
else [ [ self undoManager ] setActionName : [ NSString stringWithFormat : NSLocalizedString ( @ "Attributes Change for '%@'" , nil ) , [ resource name ] ] ] ;
}
- ( void ) resourceDataDidChange : ( NSNotification * ) notification
{
[ self updateChangeCount : NSChangeDone ] ;
2002-02-14 23:24:53 +00:00
}
# pragma mark -
2008-07-31 20:27:55 +00:00
# pragma mark Edit Operations
2002-02-14 23:24:53 +00:00
2002-11-13 03:35:54 +00:00
- ( IBAction ) cut : ( id ) sender
{
[ self copy : sender ] ;
[ self clear : sender ] ;
}
- ( IBAction ) copy : ( id ) sender
{
2008-07-31 20:27:55 +00:00
# pragma unused ( sender )
2002-11-13 03:35:54 +00:00
NSArray * selectedItems = [ outlineView selectedItems ] ;
NSPasteboard * pb = [ NSPasteboard pasteboardWithName : NSGeneralPboard ] ;
[ pb declareTypes : [ NSArray arrayWithObject : RKResourcePboardType ] owner : self ] ;
[ pb setData : [ NSArchiver archivedDataWithRootObject : selectedItems ] forType : RKResourcePboardType ] ;
}
- ( IBAction ) paste : ( id ) sender
{
2008-07-31 20:27:55 +00:00
# pragma unused ( sender )
2002-11-13 03:35:54 +00:00
NSPasteboard * pb = [ NSPasteboard pasteboardWithName : NSGeneralPboard ] ;
2008-07-31 20:27:55 +00:00
if ( [ pb availableTypeFromArray : [ NSArray arrayWithObject : RKResourcePboardType ] ] )
2002-11-13 03:35:54 +00:00
[ self pasteResources : [ NSUnarchiver unarchiveObjectWithData : [ pb dataForType : RKResourcePboardType ] ] ] ;
}
- ( void ) pasteResources : ( NSArray * ) pastedResources
{
Resource * resource ;
NSEnumerator * enumerator = [ pastedResources objectEnumerator ] ;
2008-07-31 20:27:55 +00:00
while ( resource = ( Resource * ) [ enumerator nextObject ] )
2002-11-13 03:35:54 +00:00
{
// check resource type / ID is available
2008-07-31 20:27:55 +00:00
if ( [ dataSource resourceOfType : [ resource type ] andID : [ resource resID ] ] = = nil )
2002-11-13 03:35:54 +00:00
{
// resource slot is available , paste this one in
[ dataSource addResource : resource ] ;
}
else
{
// resource slot is ocupied , ask user what to do
NSMutableArray * remainingResources = [ [ NSMutableArray alloc ] initWithCapacity : 1 ] ;
[ remainingResources addObject : resource ] ;
[ remainingResources addObjectsFromArray : [ enumerator allObjects ] ] ;
2008-07-31 20:27:55 +00:00
NSBeginAlertSheet ( @ "Paste Error" , @ "Unique ID" , @ "Skip" , @ "Overwrite" , mainWindow , self , NULL , @ selector ( overwritePasteSheetDidDismiss : returnCode : contextInfo : ) , remainingResources , @ "There already exists a resource of type %@ with ID %@. Do you wish to assign the pasted resource a unique ID, overwrite the existing resource, or skip pasting of this resource?" , [ resource type ] , [ resource resID ] ) ;
2002-11-13 03:35:54 +00:00
}
}
}
- ( void ) overwritePasteSheetDidDismiss : ( NSWindow * ) sheet returnCode : ( int ) returnCode contextInfo : ( void * ) contextInfo
{
NSMutableArray * remainingResources = [ NSMutableArray arrayWithArray : [ ( NSArray * ) contextInfo autorelease ] ] ;
Resource * resource = [ remainingResources objectAtIndex : 0 ] ;
2008-07-31 20:27:55 +00:00
if ( returnCode = = NSAlertDefaultReturn ) // unique ID
2002-11-13 03:35:54 +00:00
{
Resource * newResource = [ Resource resourceOfType : [ resource type ] andID : [ dataSource uniqueIDForType : [ resource type ] ] withName : [ resource name ] andAttributes : [ resource attributes ] data : [ resource data ] ] ;
[ dataSource addResource : newResource ] ;
}
2008-07-31 20:27:55 +00:00
else if ( NSAlertOtherReturn ) // overwrite
2002-11-13 03:35:54 +00:00
{
[ dataSource removeResource : [ dataSource resourceOfType : [ resource type ] andID : [ resource resID ] ] ] ;
[ dataSource addResource : resource ] ;
}
2008-07-31 20:27:55 +00:00
// else if ( NSAlertAlternateReturn ) // skip
2002-11-13 03:35:54 +00:00
// remove top resource and continue paste
[ remainingResources removeObjectAtIndex : 0 ] ;
[ self pasteResources : remainingResources ] ;
}
2002-02-14 23:24:53 +00:00
- ( IBAction ) clear : ( id ) sender
2002-05-31 17:31:41 +00:00
{
2008-07-31 20:27:55 +00:00
# pragma unused ( sender )
if ( [ prefs boolForKey : @ "DeleteResourceWarning" ] )
2002-05-31 17:31:41 +00:00
{
2008-07-31 20:27:55 +00:00
NSBeginCriticalAlertSheet ( @ "Delete Resource" , @ "Delete" , @ "Cancel" , nil , [ self mainWindow ] , self , @ selector ( deleteResourcesSheetDidEnd : returnCode : contextInfo : ) , NULL , nil , @ "Please confirm you wish to delete the selected resources." ) ;
2002-05-31 17:31:41 +00:00
}
else [ self deleteSelectedResources ] ;
}
2002-11-13 03:35:54 +00:00
- ( void ) deleteResourcesSheetDidEnd : ( NSWindow * ) sheet returnCode : ( int ) returnCode contextInfo : ( void * ) contextInfo
2002-05-31 17:31:41 +00:00
{
2008-07-31 20:27:55 +00:00
# pragma unused ( contextInfo )
if ( returnCode = = NSOKButton )
2002-05-31 17:31:41 +00:00
[ self deleteSelectedResources ] ;
}
- ( void ) deleteSelectedResources
2002-02-14 23:24:53 +00:00
{
Resource * resource ;
2002-03-31 12:42:07 +00:00
NSEnumerator * enumerator ;
NSArray * selectedItems = [ outlineView selectedItems ] ;
2002-02-14 23:24:53 +00:00
// enumerate through array and delete resources
2002-03-31 12:42:07 +00:00
[ [ self undoManager ] beginUndoGrouping ] ;
enumerator = [ selectedItems reverseObjectEnumerator ] ; // reverse so an undo will replace items in original order
2008-07-31 20:27:55 +00:00
while ( resource = [ enumerator nextObject ] )
2002-02-14 23:24:53 +00:00
{
[ dataSource removeResource : resource ] ;
2008-07-31 20:27:55 +00:00
if ( [ [ resource name ] length ] = = 0 )
2002-02-14 23:24:53 +00:00
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "Delete Resource" , nil ) ] ;
2008-07-31 20:27:55 +00:00
else [ [ self undoManager ] setActionName : [ NSString stringWithFormat : NSLocalizedString ( @ "Delete Resource '%@'" , nil ) , [ resource name ] ] ] ;
2002-02-14 23:24:53 +00:00
}
[ [ self undoManager ] endUndoGrouping ] ;
// generalise undo name if more than one was deleted
2008-07-31 20:27:55 +00:00
if ( [ outlineView numberOfSelectedRows ] > 1 )
2002-02-14 23:24:53 +00:00
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "Delete Resources" , nil ) ] ;
2003-08-01 22:23:50 +00:00
// deselect resources ( otherwise other resources move into selected rows ! )
2002-02-14 23:24:53 +00:00
[ outlineView deselectAll : self ] ;
}
2002-02-07 03:45:43 +00:00
# pragma mark -
2008-07-31 20:27:55 +00:00
# pragma mark Accessors
2002-02-06 20:57:56 +00:00
2002-02-23 03:40:24 +00:00
- ( NSWindow * ) mainWindow
2001-10-19 19:41:13 +00:00
{
2002-02-23 03:40:24 +00:00
return mainWindow ;
2001-10-19 19:41:13 +00:00
}
- ( ResourceDataSource * ) dataSource
{
return dataSource ;
}
2002-02-23 03:40:24 +00:00
- ( NSOutlineView * ) outlineView
{
return outlineView ;
}
2002-02-12 01:24:53 +00:00
- ( NSArray * ) resources
{
return resources ;
}
2008-07-31 20:27:55 +00:00
- ( NSData * ) creator
2002-03-31 12:00:02 +00:00
{
return creator ;
}
2008-07-31 20:27:55 +00:00
- ( NSData * ) type
2002-03-31 12:00:02 +00:00
{
return type ;
}
- ( IBAction ) creatorChanged : ( id ) sender
{
2008-07-31 20:27:55 +00:00
unsigned long newCreator = 0 x00 ; // creator is nil by default
NSData * creatorData = [ [ sender stringValue ] dataUsingEncoding : NSMacOSRomanStringEncoding ] ;
// NSLog ( @ "creatorChanged: [sender stringValue] = '%@'; creatorData = '%@'" , [ sender stringValue ] , creatorData ) ;
if ( creatorData && [ creatorData length ] > 0 )
{
newCreator = ' ' ; // pad with spaces if not nil
[ creatorData getBytes : & newCreator length : ( [ creatorData length ] < 4 ? [ creatorData length ] : 4 ) ] ;
}
[ self setCreator : [ NSData dataWithBytes : & newCreator length : 4 ] ] ;
// NSLog ( @ "Creator changed to '%@'" , [ [ [ NSString alloc ] initWithBytes : & newCreator length : 4 encoding : NSMacOSRomanStringEncoding ] autorelease ] ) ;
2002-03-31 12:00:02 +00:00
}
- ( IBAction ) typeChanged : ( id ) sender
{
2008-07-31 20:27:55 +00:00
unsigned long newType = 0 x00 ;
NSData * typeData = [ [ sender stringValue ] dataUsingEncoding : NSMacOSRomanStringEncoding ] ;
// NSLog ( @ "typeChanged: [sender stringValue] = '%@'; typeData = '%@'" , [ sender stringValue ] , typeData ) ;
if ( typeData && [ typeData length ] > 0 )
{
newType = ' ' ;
[ typeData getBytes : & newType length : ( [ typeData length ] < 4 ? [ typeData length ] : 4 ) ] ;
}
[ self setType : [ NSData dataWithBytes : & newType length : 4 ] ] ;
// NSLog ( @ "Type changed to '%@'" , [ [ [ NSString alloc ] initWithBytes : & newType length : 4 encoding : NSMacOSRomanStringEncoding ] autorelease ] ) ;
2002-03-31 12:00:02 +00:00
}
2008-07-31 20:27:55 +00:00
- ( BOOL ) setCreator : ( NSData * ) newCreator
2002-03-31 12:00:02 +00:00
{
2008-07-31 20:27:55 +00:00
if ( ! [ newCreator isEqualToData : creator ] )
2002-03-31 12:00:02 +00:00
{
id old = creator ;
2008-07-31 20:27:55 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : DocumentInfoWillChangeNotification object : [ NSDictionary dictionaryWithObjectsAndKeys : self , @ "NSDocument" , newCreator , @ "creator" , nil ] ] ;
2002-03-31 12:00:02 +00:00
[ [ self undoManager ] registerUndoWithTarget : self selector : @ selector ( setCreator : ) object : creator ] ;
2008-07-31 20:27:55 +00:00
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "Change Creator Code" , nil ) ] ;
2002-03-31 12:00:02 +00:00
creator = [ newCreator copy ] ;
[ old release ] ;
2008-07-31 20:27:55 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : DocumentInfoDidChangeNotification object : [ NSDictionary dictionaryWithObjectsAndKeys : self , @ "NSDocument" , creator , @ "creator" , nil ] ] ;
return YES ;
2002-03-31 12:00:02 +00:00
}
2008-07-31 20:27:55 +00:00
else return NO ;
2002-03-31 12:00:02 +00:00
}
2008-07-31 20:27:55 +00:00
- ( BOOL ) setType : ( NSData * ) newType
2002-03-31 12:00:02 +00:00
{
2008-07-31 20:27:55 +00:00
if ( ! [ newType isEqualToData : type ] )
2002-03-31 12:00:02 +00:00
{
id old = type ;
2008-07-31 20:27:55 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : DocumentInfoWillChangeNotification object : [ NSDictionary dictionaryWithObjectsAndKeys : self , @ "NSDocument" , newType , @ "type" , nil ] ] ;
2002-03-31 12:00:02 +00:00
[ [ self undoManager ] registerUndoWithTarget : self selector : @ selector ( setType : ) object : type ] ;
2008-07-31 20:27:55 +00:00
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "Change File Type" , nil ) ] ;
2002-03-31 12:00:02 +00:00
type = [ newType copy ] ;
[ old release ] ;
2008-07-31 20:27:55 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : DocumentInfoDidChangeNotification object : [ NSDictionary dictionaryWithObjectsAndKeys : self , @ "NSDocument" , type , @ "type" , nil ] ] ;
return YES ;
2002-03-31 12:00:02 +00:00
}
2008-07-31 20:27:55 +00:00
else return NO ;
2002-03-31 12:00:02 +00:00
}
2008-07-31 20:27:55 +00:00
- ( BOOL ) setCreator : ( NSData * ) newCreator andType : ( NSData * ) newType
2002-03-31 12:00:02 +00:00
{
2008-07-31 20:27:55 +00:00
BOOL creatorChanged , typeChanged ;
2002-03-31 12:00:02 +00:00
[ [ self undoManager ] beginUndoGrouping ] ;
2008-07-31 20:27:55 +00:00
creatorChanged = [ self setCreator : newCreator ] ;
typeChanged = [ self setType : newType ] ;
2002-03-31 12:00:02 +00:00
[ [ self undoManager ] endUndoGrouping ] ;
2008-07-31 20:27:55 +00:00
if ( creatorChanged && typeChanged )
[ [ self undoManager ] setActionName : NSLocalizedString ( @ "Change Creator & Type" , nil ) ] ;
return ( creatorChanged || typeChanged ) ;
2003-08-01 22:23:50 +00:00
}
2002-03-31 12:00:02 +00:00
@ end