Added save dialog to Hex Editor and finished Boom & Char Nova Tools

This commit is contained in:
Nicholas Shanks 2002-12-31 19:06:40 +00:00
parent a484060e30
commit 9f6f97977b
40 changed files with 867 additions and 270 deletions

View File

@ -667,7 +667,7 @@ pascal OSStatus CarbonEventUpdateMenus( EventHandlerCallRef callRef, EventRef ev
{
#pragma unused( callRef, event, userData )
OSStatus error = eventNotHandledErr;
Boolean fileOpen = (Boolean) FrontNonFloatingWindow();
Boolean fileOpen = (Boolean) (FrontNonFloatingWindow() != NULL);
// application menu (passing null causes all menus to be searched)
EnableCommand( null, kMenuCommandAbout, true );
@ -1046,6 +1046,7 @@ OSStatus ShowAboutBox( void )
SetRect( &creationBounds, 0, 0, 300, 300 );
OffsetRect( &creationBounds, 50, 50 );
OSStatus error = CreateNewWindow( kDocumentWindowClass, kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute, &creationBounds, &window );
if( error ) return error;
ControlRef picControl;
ControlButtonContentInfo content;

View File

@ -8,7 +8,7 @@ extern globals g;
/*** CREATOR ***/
EditorWindow::EditorWindow( FileWindowPtr ownerFile, ResourceObjectPtr targetResource, WindowRef inputWindow ) : PlugWindow( ownerFile )
{
OSStatus error = noErr;
// OSStatus error = noErr;
// set default variables
window = inputWindow;

View File

@ -369,7 +369,7 @@ pascal OSStatus FileWindowEventHandler( EventHandlerCallRef callRef, EventRef ev
pascal OSStatus FileWindowUpdateMenus( EventHandlerCallRef callRef, EventRef event, void *userData )
{
#pragma unused( callRef, event )
OSStatus error = eventNotHandledErr;
// OSStatus error = eventNotHandledErr;
// get file window
FileWindowPtr file = (FileWindowPtr) userData;
@ -1602,7 +1602,7 @@ OSStatus FileWindow::OpenResource( DataBrowserItemID itemID, MenuCommand command
#pragma unused( command )
// get opened resource
OSStatus error = noErr;
Boolean stop = false;
// Boolean stop = false;
ResourceObjectPtr resource = GetResource( itemID );
// check for null resource

View File

@ -200,10 +200,10 @@ OSStatus FileWindow::DisplayModelessAskSaveChangesDialog( void )
{
OSStatus error;
NavEventUPP eventProc = NewNavEventUPP( ModelessAskSaveChangesHandler );
NavPreviewUPP previewProc = null;
/* NavPreviewUPP previewProc = null;
NavObjectFilterUPP filterProc = null;
NavTypeListHandle typeList = null;
NavAskSaveChangesAction action = g.quitting? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
*/ NavAskSaveChangesAction action = g.quitting? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
NavDialogCreationOptions options;
error = NavGetDefaultDialogCreationOptions( &options );
options.parentWindow = window;
@ -438,7 +438,7 @@ pascal void ModelessAskSaveChangesHandler( const NavEventCallbackMessage callBac
pascal void ModelessPutFileHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
OSStatus error = noErr;
FileWindowPtr file = (FileWindowPtr) callBackUD;
// FileWindowPtr file = (FileWindowPtr) callBackUD;
switch( callBackSelector )
{
case kNavCBUserAction:
@ -464,7 +464,7 @@ pascal void ModelessPutFileHandler( const NavEventCallbackMessage callBackSelect
pascal void ModelessAskDiscardChangesHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
OSStatus error = noErr;
FileWindowPtr file = (FileWindowPtr) callBackUD;
// FileWindowPtr file = (FileWindowPtr) callBackUD;
switch( callBackSelector )
{
case kNavCBUserAction:

View File

@ -55,7 +55,7 @@ Plug_PlugInRef Host_GetPlugRef( WindowRef window )
Plug_ResourceRef Host_GetResource( ResType type, SInt32 resID, Plug_ResourceRef sameFileAsResource )
{
FilWindowPtr file;
// FileWindowPtr file;
if( sameFileAsResource != NULL )
{
// file = ((ResourceObjectPtr) sameFileAsResource)->file;

View File

@ -25,85 +25,89 @@ InspectorWindow::InspectorWindow( void )
SetRect( &creationBounds, 0, 0, kInspectorWindowWidth, kInspectorWindowHeight );
OffsetRect( &creationBounds, 520, 45 );
OSStatus error = CreateNewWindow( kFloatingWindowClass, kWindowStandardFloatingAttributes | kWindowStandardHandlerAttribute, &creationBounds, &window );
GetIndString( windowName, kWindowNameStrings, kStringInspectorWindowName );
SetWindowTitle( window, windowName );
SetWindowKind( window, kInspectorWindowKind );
SetThemeWindowBackground( window, kThemeBrushUtilityWindowBackgroundActive, false );
// install window event handler
EventHandlerRef ref = null;
EventHandlerUPP eventHandler = NewEventHandlerUPP( CloseInspectorWindow );
EventTypeSpec events[] = { { kEventClassWindow, kEventWindowClose } };
InstallWindowEventHandler( window, eventHandler, GetEventTypeCount(events), (EventTypeSpec *) &events, this, &ref );
// create root control
Rect bounds;
if( g.systemVersion < kMacOSX )
if( !error )
{
ControlRef root;
CreateRootControl( window, &root );
GetIndString( windowName, kWindowNameStrings, kStringInspectorWindowName );
SetWindowTitle( window, windowName );
SetWindowKind( window, kInspectorWindowKind );
SetThemeWindowBackground( window, kThemeBrushUtilityWindowBackgroundActive, false );
// install window event handler
EventHandlerRef ref = null;
EventHandlerUPP eventHandler = NewEventHandlerUPP( CloseInspectorWindow );
EventTypeSpec events[] = { { kEventClassWindow, kEventWindowClose } };
InstallWindowEventHandler( window, eventHandler, GetEventTypeCount(events), (EventTypeSpec *) &events, this, &ref );
// create root control
Rect bounds;
if( g.systemVersion < kMacOSX )
{
ControlRef root;
CreateRootControl( window, &root );
}
// create image well
ControlRef imageWell;
ControlButtonContentInfo content;
content.contentType = kControlNoContent;
SetRect( &bounds, 0, 0, 44, 44 );
OffsetRect( &bounds, 8, 8 );
CreateImageWellControl( window, &bounds, &content, &imageWell );
// create static text controls
Rect windowRect;
ControlRef name, type, id;
ControlFontStyleRec fontStyle;
fontStyle.flags = kControlUseFontMask + kControlUseJustMask;
fontStyle.font = kControlFontSmallSystemFont;
fontStyle.just = teJustLeft;
GetWindowPortBounds( window, &windowRect );
SetRect( &bounds, windowRect.left +60, windowRect.top +8, windowRect.right - windowRect.left -8, windowRect.top +36 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &name );
fontStyle.font = kControlFontSmallBoldSystemFont;
SetRect( &bounds, windowRect.left +60, windowRect.top +38, windowRect.right - windowRect.left -70, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &type );
SetRect( &bounds, windowRect.right - windowRect.left -70, windowRect.top +38, windowRect.right - windowRect.left -8, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &id );
// create group control
ControlRef group;
GetWindowPortBounds( window, &bounds );
InsetRect( &bounds, 8, 8 );
bounds.top += kInspectorHeaderHeight;
CreateGroupBoxControl( window, &bounds, CFSTR("Attributes"), true, &group );
// create checkboxes
ControlRef changedBox, preloadBox, protectedBox,
lockedBox, purgeableBox, sysHeapBox;
InsetRect( &bounds, 4, 4 );
bounds.top = bounds.bottom - kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("System Heap"), kControlCheckBoxUncheckedValue, true, &sysHeapBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Purgeable"), kControlCheckBoxUncheckedValue, true, &purgeableBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Locked"), kControlCheckBoxUncheckedValue, true, &lockedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Protected"), kControlCheckBoxUncheckedValue, true, &protectedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Preload"), kControlCheckBoxUncheckedValue, true, &preloadBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Changed"), kControlCheckBoxUncheckedValue, true, &changedBox );
// embed controls
EmbedControl( changedBox, group );
EmbedControl( preloadBox, group );
EmbedControl( protectedBox, group );
EmbedControl( lockedBox, group );
EmbedControl( purgeableBox, group );
EmbedControl( sysHeapBox, group );
}
// create image well
ControlRef imageWell;
ControlButtonContentInfo content;
content.contentType = kControlNoContent;
SetRect( &bounds, 0, 0, 44, 44 );
OffsetRect( &bounds, 8, 8 );
CreateImageWellControl( window, &bounds, &content, &imageWell );
// create static text controls
Rect windowRect;
ControlRef name, type, id;
ControlFontStyleRec fontStyle;
fontStyle.flags = kControlUseFontMask + kControlUseJustMask;
fontStyle.font = kControlFontSmallSystemFont;
fontStyle.just = teJustLeft;
GetWindowPortBounds( window, &windowRect );
SetRect( &bounds, windowRect.left +60, windowRect.top +8, windowRect.right - windowRect.left -8, windowRect.top +36 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &name );
fontStyle.font = kControlFontSmallBoldSystemFont;
SetRect( &bounds, windowRect.left +60, windowRect.top +38, windowRect.right - windowRect.left -70, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &type );
SetRect( &bounds, windowRect.right - windowRect.left -70, windowRect.top +38, windowRect.right - windowRect.left -8, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &id );
// create group control
ControlRef group;
GetWindowPortBounds( window, &bounds );
InsetRect( &bounds, 8, 8 );
bounds.top += kInspectorHeaderHeight;
CreateGroupBoxControl( window, &bounds, CFSTR("Attributes"), true, &group );
// create checkboxes
ControlRef changedBox, preloadBox, protectedBox,
lockedBox, purgeableBox, sysHeapBox;
InsetRect( &bounds, 4, 4 );
bounds.top = bounds.bottom - kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("System Heap"), kControlCheckBoxUncheckedValue, true, &sysHeapBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Purgeable"), kControlCheckBoxUncheckedValue, true, &purgeableBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Locked"), kControlCheckBoxUncheckedValue, true, &lockedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Protected"), kControlCheckBoxUncheckedValue, true, &protectedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Preload"), kControlCheckBoxUncheckedValue, true, &preloadBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Changed"), kControlCheckBoxUncheckedValue, true, &changedBox );
// embed controls
EmbedControl( changedBox, group );
EmbedControl( preloadBox, group );
EmbedControl( protectedBox, group );
EmbedControl( lockedBox, group );
EmbedControl( purgeableBox, group );
EmbedControl( sysHeapBox, group );
else window = NULL;
#else
if( g.useAppearance && g.systemVersion >= kMacOS8 )
window = GetNewCWindow( kFileWindow8, null, kFirstWindowOfClass );
@ -111,10 +115,14 @@ InspectorWindow::InspectorWindow( void )
window = GetNewCWindow( kFileWindow7, null, kFirstWindowOfClass );
#endif
// update and show window
Update();
ShowWindow( window );
g.inspector = this;
if( window )
{
// update and show window
Update();
ShowWindow( window );
g.inspector = this;
}
else g.inspector = NULL;
}
/*** DESTRUCTOR ***/

View File

@ -5,7 +5,7 @@
- (FSRef *)createFSRef
{
FSRef *fsRef = NULL;
OSStatus error = FSPathMakeRef( [self fileSystemRepresentation], &fsRef, NULL );
OSStatus error = FSPathMakeRef( [self fileSystemRepresentation], fsRef, NULL );
if( error == noErr )
return fsRef;
return NULL;
@ -15,10 +15,10 @@
{
FSRef *fsRef = NULL;
FSSpec *fsSpec = NULL;
OSStatus error = FSPathMakeRef( [self fileSystemRepresentation], &fsRef, NULL );
OSStatus error = FSPathMakeRef( [self fileSystemRepresentation], fsRef, NULL );
if( error == noErr )
{
error = FSGetCatalogInfo( &fsRef, kFSCatInfoNone, NULL, NULL, fsSpec, NULL );
error = FSGetCatalogInfo( fsRef, kFSCatInfoNone, NULL, NULL, fsSpec, NULL );
if( error == noErr )
return fsSpec;
}

View File

@ -1,7 +1,7 @@
#import <Foundation/Foundation.h>
#import "ResKnifeResourceProtocol.h"
@interface Resource : NSObject <NSCoding, ResKnifeResourceProtocol>
@interface Resource : NSObject <NSCopying, NSCoding, ResKnifeResourceProtocol>
{
@private
// flags

View File

@ -130,6 +130,12 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone
{
Resource *copy = [[Resource alloc] initWithType:type andID:resID withName:name andAttributes:attributes data:[data copy]];
return copy;
}
/* Accessors */
- (void)touch
@ -284,7 +290,7 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
- (NSString *)description
{
return [NSString stringWithFormat:@"\nName: %@\nType: %@ ID: %@\nModified: %@", name, type, resID, dirty? @"YES":@"NO"];
return [NSString stringWithFormat:@"\n%@\nName: %@\nType: %@ ID: %@\nSize: %d Modified: %@", [super description], name, type, resID, [data length], dirty? @"YES":@"NO"];
}
@end

View File

@ -310,10 +310,11 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
NSBundle *templateEditor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"Template Editor.plugin"]];
// 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!
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 /*&& [[templateEditor principalClass] respondsToSelector:@selector(initWithResources:)]*/ )
{
// 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.

View File

@ -124,7 +124,7 @@
// get the superclass to draw the text stuff
[super drawWithFrame:cellFrame inView:controlView];
}
/*
- (NSSize)cellSize
{
NSSize cellSize = [super cellSize];
@ -132,5 +132,5 @@
cellSize.width += (image? [image size].width:0) + 3;
return cellSize;
}
*/
@end

View File

@ -3,9 +3,9 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>681 234 356 240 0 0 1600 1002 </string>
<string>366 155 356 240 0 0 1024 746 </string>
<key>IBFramework Version</key>
<string>286.0</string>
<string>283.0</string>
<key>IBGroupedObjects</key>
<dict>
<key>0</key>
@ -26,6 +26,6 @@
<integer>7</integer>
</array>
<key>IBSystem Version</key>
<string>6F21</string>
<string>6G30</string>
</dict>
</plist>

View File

@ -5,7 +5,7 @@
/* FORM DELEGATION METHOD */
- (void)controlTextDidEndEditing:(NSNotification *)aNotification
- (void)controlTextDidEndEditing:(NSNotification *)notification
{
[self updateStrings];
}
@ -23,6 +23,16 @@
- (IBAction)showFindSheet:(id)sender
{
// load window so I can play with boxes
[self window];
// enable/disable boxes
[searchSelectionOnlyBox setEnabled:([(NSTextView *)[[sender window] firstResponder] rangeForUserTextChange].length != 0)];
// set inital vales
if( ![searchSelectionOnlyBox isEnabled] ) [searchSelectionOnlyBox setIntValue:0];
// show sheet
[NSApp beginSheet:[self window] modalForWindow:[sender window] modalDelegate:self didEndSelector:NULL contextInfo:nil];
}

View File

@ -5,6 +5,7 @@
@interface HexTextView : NSTextView
{
}
- (IBAction)clear:(id)sender;
- (IBAction)pasteAsASCII:(id)sender;
- (IBAction)pasteAsHex:(id)sender;
- (IBAction)pasteAsUnicode:(id)sender;

View File

@ -444,7 +444,7 @@ static NSRange draggedRange;
[newData replaceBytesInRange:range withBytes:[newBytes bytes] length:[newBytes length]];
[[(HexWindowController *)[[self window] windowController] resource] setData:newData];
[self setSelectedRange:NSMakeRange(range.location + [newBytes length], 0)];
[[self window] setDocumentEdited:YES];
// [[self window] setDocumentEdited:YES]; // moved to window controller's -resourceDataDidChange: notification method
// record undo with new data object
[[[[self window] undoManager] prepareWithInvocationTarget:self] editData:newData replaceBytesInRange:newRange withData:oldBytes];

View File

@ -21,6 +21,8 @@
NSUndoManager *undoManager;
id <ResKnifeResourceProtocol> resource;
id <ResKnifeResourceProtocol> backup;
BOOL liveEdit;
int bytesPerRow;
}
@ -30,10 +32,16 @@
// show find sheet
- (IBAction)showFind:(id)sender;
// save sheet methods
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
- (void)saveResource;
- (void)revertResource;
// normal methods
- (void)viewDidScroll:(NSNotification *)notification;
- (void)resourceNameDidChange:(NSNotification *)notification;
- (void)resourceDataDidChange:(NSNotification *)notification;
- (void)resourceWasSaved:(NSNotification *)notification;
- (void)refreshData:(NSData *)data;
// accessors

View File

@ -11,7 +11,17 @@
// one instance of your principal class will be created for every resource the user wants to edit (similar to Windows apps)
undoManager = [[NSUndoManager alloc] init];
resource = [newResource retain];
liveEdit = NO;
if( liveEdit )
{
resource = [newResource retain];
backup = [newResource copy];
}
else
{
resource = [newResource copy];
backup = [newResource retain];
}
bytesPerRow = 16;
// load the window from the nib file and set it's title
@ -30,7 +40,7 @@
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[(id)resource autorelease];
[(id)resource release];
[super dealloc];
}
@ -59,6 +69,8 @@
// we don't want this notification until we have a window! (Only register for notifications on the resource we're editing)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceNameDidChange:) name:ResourceNameDidChangeNotification object:resource];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceWasSavedNotification object:resource];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceWasSavedNotification object:backup];
// put other notifications here too, just for togetherness
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[offset enclosingScrollView] contentView]];
@ -105,11 +117,55 @@
[pasteItem setKeyEquivalentModifierMask:NSCommandKeyMask];
}
/*
- (BOOL)windowShouldClose:(NSWindow *)sender
- (BOOL)windowShouldClose:(id)sender
{
return [sender isDocumentEdited];
}*/
if( [[self window] isDocumentEdited] )
{
NSBeginAlertSheet( @"Do you want to save the changes you made to this resource?", @"Save", @"DonÕt Save", @"Cancel", sender, self, @selector(saveSheetDidClose:returnCode:contextInfo:), nil, nil, @"Your changes will be lost if you don't save them." );
return NO;
}
else return YES;
}
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
switch( returnCode )
{
case NSAlertDefaultReturn: // save
[self saveResource];
[[self window] close];
break;
case NSAlertAlternateReturn: // don't save
[self revertResource];
[[self window] close];
break;
case NSAlertOtherReturn: // cancel
break;
}
}
- (void)saveResource
{
if( liveEdit )
{
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillBeSavedNotification object:resource];
[backup setData:[resource data]];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWasSavedNotification object:resource];
}
else
{
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillBeSavedNotification object:backup];
[backup setData:[resource data]];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWasSavedNotification object:backup];
}
}
- (void)revertResource
{
[resource setData:[backup data]];
}
- (IBAction)showFind:(id)sender
{
@ -127,7 +183,7 @@
NSClipView *asciiClip = [[ascii enclosingScrollView] contentView];
// due to a bug in -[NSView setPostsBoundsChangedNotifications:] (it basically doesn't work), I am having to work around it by removing myself from the notification center and restoring things later on!
// update, Apple say this isn't their bug.
// update, Apple say this isn't their bug. Yeah, right!
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewBoundsDidChangeNotification object:nil];
// when a view scrolls, update the other two
@ -169,7 +225,36 @@
{
// ensure it's our resource which got changed (should always be true, we don't register for other resource notifications)
if( [notification object] == (id)resource )
{
[self refreshData:[resource data]];
[self setDocumentEdited:YES];
}
}
- (void)resourceWasSaved:(NSNotification *)notification
{
NSLog( @"%@; %@; %@", [notification object], resource, backup );
if( [notification object] == (id)resource )
{
// if resource gets saved, liveEdit is true and this resource is saving
[backup setData:[resource data]];
[self setDocumentEdited:NO];
}
else if( [notification object] == (id)backup && !liveEdit )
{
// backup will get saved by this resource if liveEdit is false, rather than the 'resource' variable
// but really the data to preserve is in the resource variable
[backup setData:[resource data]];
// [self refreshData:[resource data]];
[self setDocumentEdited:NO];
}
else if( [notification object] == (id)backup )
{
// backup will get saved by another editor too if liveEdit is false
[resource setData:[backup data]];
// [self refreshData:[resource data]];
[self setDocumentEdited:NO];
}
}
- (void)refreshData:(NSData *)data;

View File

@ -12,10 +12,12 @@ NSString *ResourceTypeWillChangeNotification = @"ResourceTypeWillChangeNotifica
NSString *ResourceIDWillChangeNotification = @"ResourceIDWillChangeNotification";
NSString *ResourceAttributesWillChangeNotification = @"ResourceAttributesWillChangeNotification";
NSString *ResourceDataWillChangeNotification = @"ResourceDataWillChangeNotification";
NSString *ResourceWillBeSavedNotification = @"ResourceWillBeSavedNotification";
NSString *ResourceNameDidChangeNotification = @"ResourceNameDidChangeNotification";
NSString *ResourceTypeDidChangeNotification = @"ResourceTypeDidChangeNotification";
NSString *ResourceIDDidChangeNotification = @"ResourceIDDidChangeNotification";
NSString *ResourceAttributesDidChangeNotification = @"ResourceAttributesDidChangeNotification";
NSString *ResourceDataDidChangeNotification = @"ResourceDataDidChangeNotification";
NSString *ResourceDidChangeNotification = @"ResourceDidChangeNotification";
NSString *ResourceDidChangeNotification = @"ResourceDidChangeNotification";
NSString *ResourceWasSavedNotification = @"ResourceWasSavedNotification";

View File

@ -39,10 +39,12 @@ extern NSString *ResourceTypeWillChangeNotification;
extern NSString *ResourceIDWillChangeNotification;
extern NSString *ResourceAttributesWillChangeNotification;
extern NSString *ResourceDataWillChangeNotification;
extern NSString *ResourceWillBeSavedNotification;
extern NSString *ResourceNameDidChangeNotification;
extern NSString *ResourceTypeDidChangeNotification;
extern NSString *ResourceIDDidChangeNotification;
extern NSString *ResourceAttributesDidChangeNotification;
extern NSString *ResourceDataDidChangeNotification;
extern NSString *ResourceDidChangeNotification;
extern NSString *ResourceDidChangeNotification;
extern NSString *ResourceWasSavedNotification;

View File

@ -4,8 +4,7 @@
{
NSString *type;
NSString *label;
NSMutableArray *subelements; // elements of a list type have a sub-array of elements
union // for resource data only, ignored for templates
union // for resource arrays only, ignored for TMPL arrays
{
NSString *string;
NSNumber *number;
@ -19,7 +18,6 @@
- (NSString *)label;
- (NSString *)type;
- (NSMutableArray *)subelements;
- (unsigned long)typeAsLong;
- (NSString *)string;
- (void)setString:(NSString *)string;

View File

@ -20,7 +20,7 @@
- (id)copy
{
Element *element = [[Element alloc] initWithType:type andLabel:label];
// copy other stuff here
// bug: copy other stuff here
return element;
}
@ -40,7 +40,7 @@
{
return *(unsigned long *)[type cString];
}
/*
- (NSMutableArray *)subelements;
{
long myType = [self typeAsLong];
@ -52,7 +52,7 @@
else subelements = nil;
return subelements;
}
*/
/* DATA ACCESSORS */
- (NSString *)string
@ -105,4 +105,9 @@
elementData.boolean = boolean;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"{ %@, %@ }", type, label];
}
@end

View File

@ -4,7 +4,7 @@
{
CLASS = TemplateWindowController;
LANGUAGE = ObjC;
OUTLETS = {fieldsMatrix = NSMatrix; };
OUTLETS = {containerView = NSView; };
SUPERCLASS = NSWindowController;
}
);

View File

@ -3,10 +3,26 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>672 193 356 240 0 0 1600 1002 </string>
<string>276 97 356 240 0 0 1024 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>22</key>
<string>114 377 480 236 0 0 1024 746 </string>
<key>45</key>
<string>163 366 480 162 0 0 1024 746 </string>
</dict>
<key>IBFramework Version</key>
<string>286.0</string>
<string>283.0</string>
<key>IBLockedObjects</key>
<array>
<integer>20</integer>
<integer>19</integer>
</array>
<key>IBOpenObjects</key>
<array>
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>6D52</string>
<string>6G30</string>
</dict>
</plist>

View File

@ -5,7 +5,7 @@
@interface TemplateWindowController : NSWindowController <ResKnifePluginProtocol>
{
IBOutlet NSMatrix *fieldsMatrix;
IBOutlet NSView *containerView;
NSMutableArray *tmpl;
NSMutableArray *res;

View File

@ -27,7 +27,7 @@
tmpl = [[NSMutableArray alloc] init];
res = [[NSMutableArray alloc] init];
[self readTemplate:va_arg( resourceList, id )]; // reads (but doesn't retain) the TMPL resource
[self readTemplate:va_arg( resourceList, id )]; // reads (but doesn't retain) the template for this resource (TMPL resource with name equal to the passed resource's type)
while( currentResource = va_arg( resourceList, id ) )
NSLog( @"too many params passed to -initWithResources: %@", [currentResource description] );
va_end( resourceList );
@ -55,7 +55,7 @@
[[self window] setTitle:[resource name]];
// parse data using pre-scanned template and create the fields as needed
[self parseData];
[self readData];
[self createUI];
// insert the resources' data into the text fields
@ -88,29 +88,94 @@
currentByte += 4;
// add element to array
// NSLog( @"Adding object %@ of type %@ to array", label, type );
[tmpl addObject:[Element elementOfType:type withLabel:label]];
}
}
}
- (void)readData
{
// tmpl == array of Elements describing the template for this resource
// res == array of either Elements or Arrays containing the resource data
// this function creates the res instance variable, filling it with data from the resource if there's data available.
unsigned long position = 0; // position (byte offset) in resource I'm currently reading from
char *data = (char *) [[resource data] bytes]; // address of initial byte of resource in memory
unsigned long templateCounter = 0; // index into template array of the current template element
Element *currentTemplateElement; // current template element
NSMutableArray *targetStack = [NSMutableArray arrayWithObject:res]; // stack of arrays (target for addition of new elements)
NSMutableArray *loopStack = [NSMutableArray array]; // stack for 'LSTB' and 'LSTC' elements
NSMutableArray *loopCountStack = [NSMutableArray array]; // stack for counting how many times to loop
// when templateCounter >= [tmpl count], loop is only exited if targetStack has more than one target (this handles empty templates)
while( templateCounter < [tmpl count] || [targetStack count] > 1 )
{
currentTemplateElement = [tmpl objectAtIndex:templateCounter];
NSLog( @"template = %@", currentTemplateElement );
/* unsigned long type = [currentTemplateElement typeAsLong];
switch( type )
{
case 'BCNT':
case 'BZCT':
[resourceElement setNumberWithLong:*(unsigned char *)(data + position)];
lim = *(unsigned char *)(data + position) + (type == 'BZCT'? 1:0);
position += 1;
break;
case 'OCNT':
case 'ZCNT':
[resourceElement setNumberWithLong:*(unsigned short *)(data + position)];
lim = *(unsigned short *)(data + position) + (type == 'ZCNT'? 1:0);
position += 2;
break;
case 'LCNT':
case 'LZCT':
[resourceElement setNumberWithLong:*(unsigned long *)(data + position)];
lim = *(unsigned long *)(data + position) + (type == 'LZCT'? 1:0);
position += 4;
break;
case 'LSTB':
case 'LSTC':
[(NSMutableArray *)[targetStack lastObject] addObject:[NSMutableArray array]];
[loopStack addObject:currentTemplateElement]; // append the template loop start object to the array
break;
default:
// [(NSMutableArray *)[targetStack lastObject] addItem:[self createElementForTemplate:currentTemplateElement
}
*/
templateCounter++;
}
}
- (void)parseData
{
unsigned long position = 0;
char *data = (char *) [resource data];
char *data = (char *) [[resource data] bytes];
// used for nesting of elements, 'target' is current object to append to, targetStack is a FILO stack of mutable array pointers
// used for nesting of elements, 'target' is current object to append to, targetStack is a FILO stack of mutable array pointers, loopStack is a stack of element indicies to the start of loops, so I can go back to the head of a loop when iterating it
NSMutableArray *target = res;
NSMutableArray *targetArray = [NSMutableArray arrayWithObject:res];
NSMutableArray *targetStack = [NSMutableArray arrayWithObject:res];
NSMutableArray *loopStack = [NSMutableArray array];
// n = current item in TMPL to read, c = loop counter, when exiting loop, go back 'c' items in the template, lim is how many times to loop, obtained from a loop count
unsigned long n = 0, c = 0, lim = 0;
// creates an array of elements containing the data in whatever format the template dictates
// array can then simply be manipulated one element at a time, or flattened to save
Element *currentTemplateElement, *resourceElement;
NSEnumerator *enumerator = [tmpl objectEnumerator];
while( currentTemplateElement = [enumerator nextObject] )
// NSEnumerator *enumerator = [tmpl objectEnumerator];
// while( currentTemplateElement = [enumerator nextObject] )
while( position < [[resource size] unsignedLongValue] )
{
currentTemplateElement = [tmpl objectAtIndex:n];
n++, c++;
unsigned long type = [currentTemplateElement typeAsLong];
resourceElement = [[currentTemplateElement copy] autorelease];
NSLog( @"tmpl element = %@; position = %d", currentTemplateElement, position );
switch( type )
{
/* Alignment */
@ -163,38 +228,60 @@
// bug: doesn't check HEXD is the last element
[resourceElement setData:[NSData dataWithBytes:(void *)(data + position) length:([[resource size] intValue] - position)]];
position = [[resource size] intValue];
break;
/* Strings */
case 'CHAR':
[resourceElement setString:[[NSString alloc] initWithData:[NSData dataWithBytes:(void *)(data + position) length:1] encoding:NSMacOSRomanStringEncoding]];
position += 1;
break;
case 'TNAM':
[resourceElement setString:[[NSString alloc] initWithData:[NSData dataWithBytes:(void *)(data + position) length:4] encoding:NSMacOSRomanStringEncoding]];
position += 4;
break;
case 'PSTR':
[resourceElement setString:[[NSString alloc] initWithData:[NSData dataWithBytes:(void *)(data + position + 1) length:*(unsigned char *)(data + position)] encoding:NSMacOSRomanStringEncoding]];
position += *(unsigned char *)(data + position) + 1;
break;
/* List Counts */
case 'BCNT':
case 'BZCT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(char *)(data + position)];
[resourceElement setNumberWithLong:*(unsigned char *)(data + position)];
lim = *(unsigned char *)(data + position) + (type == 'BZCT'? 1:0);
position += 1;
break;
case 'OCNT':
case 'ZCNT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(short *)(data + position)];
[resourceElement setNumberWithLong:*(unsigned short *)(data + position)];
lim = *(unsigned short *)(data + position) + (type == 'ZCNT'? 1:0);
position += 2;
break;
case 'LCNT':
case 'LZCT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(long *)(data + position)];
[resourceElement setNumberWithLong:*(unsigned long *)(data + position)];
lim = *(unsigned long *)(data + position) + (type == 'LZCT'? 1:0);
position += 4;
break;
/* List beginning and end */
case 'LSTB':
case 'LSTC':
target = [resourceElement subelements];
[targetArray addObject:target];
[target addObject:resourceElement]; // add list item to current target array
// target = [resourceElement subelements]; // change current array to list's sub-elements
[targetStack addObject:target]; // append sub-element array to target stack so it can be popped off afterwards
resourceElement = nil; // don't add item to it's own sub-elements later!
break;
case 'LSTE':
// bug: if there is a LSTE without a preceeding LSTB or LSTC this will crash
[targetArray removeLastObject];
target = [targetArray lastObject];
resourceElement = nil; // relies on element being previously autoreleased to avoid a leak
[targetStack removeLastObject]; // pop off current target from stack
target = [targetStack lastObject]; // set current target to whatever was second from top on the stack
resourceElement = nil; // list end items are not needed in a resource array
if( n < lim ) n -= c;
c = 0;
break;
/* Cxxx, Hxxx or P0xx */
@ -205,21 +292,26 @@
*/ char *lengthStr = (type & 0x00FFFFFF) & (3 << 24);
unsigned long length;
StringToNum(lengthStr, &length);
NSLog( @"error, Cxxx, Hxxx and P0xx unsupported, skipping %d bytes", length );
NSLog( @"error, '%@' is unsupported, skipping %d bytes", [resourceElement type], length );
resourceElement = nil; // relies on element being previously autoreleased to avoid a leak
position += length;
} break;
} // end switch
if( resourceElement ) [target addObject:resourceElement];
} // end while loop
} // end template element type switch
if( resourceElement )
{
NSLog( @"adding %@", resourceElement );
[target addObject:resourceElement];
}
} // end while position < size
NSLog( [target description] );
}
- (void)createUI
{
// iterate through res creating fields
// iterate through res (the resource element array) creating fields
[self enumerateElements:res];
NSLog( [fieldsMatrix description] );
[fieldsMatrix setNeedsDisplay];
}
- (void)enumerateElements:(NSMutableArray *)elements
@ -227,17 +319,21 @@
// iterate through the array of resource elements, creating fields
Element *currentResourceElement;
NSEnumerator *enumerator = [elements objectEnumerator];
NSLog( @"%d", [elements count] );
NSLog( @"elements in resource array = %d", [elements count] );
while( currentResourceElement = [enumerator nextObject] )
{
// if element is a container, iterate inside it first
if( [currentResourceElement subelements] )
[self enumerateElements:[currentResourceElement subelements]];
else // element is normal
// if element is a container (subelements != nil), iterate inside it first
/* if( [currentResourceElement subelements] )
{
NSFormCell *newField = [[NSFormCell alloc] initTextCell:[currentResourceElement label]];
[fieldsMatrix addRowWithCells:[NSArray arrayWithObject:[newField autorelease]]];
NSLog( @"%@ added to matrix", [newField description] );
// bug: need to indent view right
[self enumerateElements:[currentResourceElement subelements]];
// bug: need to remove indentation
}
else // element is normal
*/ {
/* NSFormCell *newField = [[NSFormCell alloc] initTextCell:[currentResourceElement label]];
[fieldsMatrix addRowWithCells:[NSArray arrayWithObject:[newField autorelease]]]; */
NSLog( [currentResourceElement description] );
}
}
}

View File

@ -54,7 +54,8 @@
- (void)parseForString:(NSString *)string sorted:(BOOL)sort
{
[self parseForString:string withinRange:NSMakeRange(-32767, 65536) sorted:sort];
// bug: for some reason +[NSNumber isBoundedByRange:] doesn't like a range with a minimum below -30,000 (such as INT16_MIN), so I'm using INT8_MIN and screw everyone using resource IDs below that :P
[self parseForString:string withinRange:NSMakeRange(INT8_MIN, INT16_MAX) sorted:sort];
}
- (void)parseForString:(NSString *)string withinRange:(NSRange)resIDRange sorted:(BOOL)sort
@ -63,6 +64,7 @@
NSString *trimmedString = [DataSource resNameFromStringValue:string];
NSEnumerator *enumerator = [[data allKeys] objectEnumerator];
[parsed removeAllObjects];
if( trimmedString == nil ) trimmedString = @"";
while( resID = [enumerator nextObject] )
{
NSString *value = [data objectForKey:resID];
@ -70,6 +72,11 @@
if( ((range.location != NSNotFound && range.length != 0) || [trimmedString isEqualToString:@""]) && [resID isBoundedByRange:resIDRange] )
[parsed addObject:[self stringValueForResID:resID]];
}
// crap hack to allow user to change the insertion point if what they typed doesn't yet match an existing resource
if( [parsed count] == 0 ) [parsed addObject:string];
// sort case insensitive if sorting is requested
if( sort ) [parsed sortUsingSelector:@selector(caseInsensitiveCompare:)];
}
@ -82,7 +89,7 @@
{
if( resID && [data objectForKey:resID] )
return [NSString stringWithFormat:@"%@ {%@}", [data objectForKey:resID], resID];
else if( [resID isEqualToNumber:[NSNumber numberWithInt:-1]] )
else if( [resID shortValue] == -1 )
return @"";
else if( resID )
return [NSString stringWithFormat:@"{%@}", resID];
@ -101,21 +108,17 @@
NS_DURING
NS_VALUERETURN( [[[NSNumber alloc] initWithInt:[[string substringWithRange:range] intValue]] autorelease], NSNumber* );
NS_HANDLER
NS_VALUERETURN( nil, NSNumber* );
NS_VALUERETURN( [NSNumber numberWithInt:-1], NSNumber* );
NS_ENDHANDLER
}
+ (NSString *)resNameFromStringValue:(NSString *)string
{
NSRange range = [string rangeOfString:@"{" options:NSBackwardsSearch];
if( range.location != NSNotFound )
{
NS_DURING
NS_VALUERETURN( [string substringToIndex:range.location -1], NSString* );
NS_HANDLER
NS_VALUERETURN( nil, NSString* );
NS_ENDHANDLER
}
if( range.location != NSNotFound && range.location > 0 )
return [string substringToIndex:range.location -1];
else if( range.location == 0 )
return nil;
else return string;
}

View File

@ -42,7 +42,8 @@
[[NSNotificationCenter defaultCenter] removeObserver:self];
[(id)resource autorelease];
[undoManager release];
[shipDataSource release]; // bug: release all data sources
[shipDataSource release];
[soundDataSource release];
[super dealloc];
}
@ -75,7 +76,7 @@
if( [[self window] isDocumentEdited] )
{
NSDictionary *errorValues = [self validateValues];
NSArray *fields = [errorValues allKeys];
NSArray *fields = [errorValues