2002-02-02 11:48:54 +00:00
# import "HexWindowController.h"
2002-02-23 03:40:24 +00:00
# import "HexTextView.h"
2002-03-21 04:02:26 +00:00
# import "FindSheetController.h"
2002-02-06 20:57:56 +00:00
2003-04-03 15:38:42 +00:00
/ *
OSStatus Plug_InitInstance ( Plug_PlugInRef plug , Plug_ResourceRef resource )
{
// init function called by carbon apps
if ( NSApplicationLoad ( ) )
{
id newResource = [ NSClassFromString ( @ "Resource" ) resourceOfType : [ NSString stringWithCString : length : 4 ] andID : [ NSNumber numberWithInt : ] withName : [ NSString stringWithCString : length : ] andAttributes : [ NSNumber numberWithUnsignedShort : ] data : [ NSData dataWithBytes : length : ] ] ;
if ( ! newResource ) return paramErr ;
id windowController = [ [ HexWindowController alloc ] initWithResource : newResource ] ;
if ( ! windowController ) return paramErr ;
else return noErr ;
}
else return paramErr ;
}
* /
2002-02-02 11:48:54 +00:00
@ implementation HexWindowController
- ( id ) initWithResource : ( id ) newResource
{
self = [ self initWithWindowNibName : @ "HexWindow" ] ;
2002-02-11 22:03:20 +00:00
if ( ! self ) return self ;
2002-02-02 11:48:54 +00:00
// one instance of your principal class will be created for every resource the user wants to edit ( similar to Windows apps )
2002-05-31 00:17:53 +00:00
undoManager = [ [ NSUndoManager alloc ] init ] ;
2002-12-31 19:06:40 +00:00
liveEdit = NO ;
if ( liveEdit )
{
resource = [ newResource retain ] ;
backup = [ newResource copy ] ;
}
else
{
resource = [ newResource copy ] ;
backup = [ newResource retain ] ;
}
2002-03-21 04:02:26 +00:00
bytesPerRow = 16 ;
2002-02-02 11:48:54 +00:00
2002-02-23 03:40:24 +00:00
// load the window from the nib file and set it ' s title
[ self window ] ; // implicitly loads nib
2003-08-05 04:08:19 +00:00
[ [ self window ] setTitle : [ resource nameForEditorWindow ] ] ;
2002-02-02 11:48:54 +00:00
return self ;
}
2002-02-06 20:57:56 +00:00
- ( void ) dealloc
{
[ [ NSNotificationCenter defaultCenter ] removeObserver : self ] ;
2003-04-03 15:38:42 +00:00
[ ( id ) resource autorelease ] ;
[ undoManager release ] ;
2002-02-06 20:57:56 +00:00
[ super dealloc ] ;
}
2002-02-02 11:48:54 +00:00
- ( void ) windowDidLoad
{
[ super windowDidLoad ] ;
2002-02-12 01:24:53 +00:00
// swap text views to instances of my class instead
2002-02-23 03:40:24 +00:00
[ offset swapForHexTextView ] ;
[ hex swapForHexTextView ] ;
[ ascii swapForHexTextView ] ;
// turn off the background for the offset column ( IB is broken when it comes to this )
[ offset setDrawsBackground : NO ] ;
[ [ offset enclosingScrollView ] setDrawsBackground : NO ] ;
// set up tab , shift - tab and enter behaviour
[ hex setFieldEditor : YES ] ;
[ ascii setFieldEditor : YES ] ;
// insert the resources ' data into the text fields
[ self refreshData : [ resource data ] ] ;
2002-11-15 15:12:42 +00:00
[ [ self window ] setResizeIncrements : NSMakeSize ( kWindowStepWidthPerChar * kWindowStepCharsPerStep , 1 ) ] ;
// min 346 , step 224 , norm 570 , step 224 , max 794
2002-02-12 01:24:53 +00:00
2002-02-14 23:24:53 +00:00
// we don ' t want this notification until we have a window ! ( Only register for notifications on the resource we ' re editing )
2002-04-30 23:44:23 +00:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceNameDidChange : ) name : ResourceNameDidChangeNotification object : resource ] ;
2002-02-14 23:24:53 +00:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceDataDidChange : ) name : ResourceDataDidChangeNotification object : resource ] ;
2002-12-31 19:06:40 +00:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceWasSaved : ) name : ResourceWasSavedNotification object : resource ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( resourceWasSaved : ) name : ResourceWasSavedNotification object : backup ] ;
2002-02-02 11:48:54 +00:00
2002-02-11 22:03:20 +00:00
// put other notifications here too , just for togetherness
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( viewDidScroll : ) name : NSViewBoundsDidChangeNotification object : [ [ offset enclosingScrollView ] contentView ] ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( viewDidScroll : ) name : NSViewBoundsDidChangeNotification object : [ [ hex enclosingScrollView ] contentView ] ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( viewDidScroll : ) name : NSViewBoundsDidChangeNotification object : [ [ ascii enclosingScrollView ] contentView ] ] ;
2002-02-02 11:48:54 +00:00
// finally , show the window
[ self showWindow : self ] ;
2002-02-06 20:57:56 +00:00
}
2002-11-13 03:35:54 +00:00
2002-11-15 15:12:42 +00:00
- ( void ) windowDidResize : ( NSNotification * ) notification
{
int width = [ [ notification object ] frame ] . size . width ;
int oldBytesPerRow = bytesPerRow ;
bytesPerRow = ( ( ( width - ( kWindowStepWidthPerChar * kWindowStepCharsPerStep ) - 122 ) / ( kWindowStepWidthPerChar * kWindowStepCharsPerStep ) ) + 1 ) * kWindowStepCharsPerStep ;
if ( bytesPerRow ! = oldBytesPerRow )
[ offset setString : [ hexDelegate offsetRepresentation : [ resource data ] ] ] ;
[ hexScroll setFrameSize : NSMakeSize ( ( bytesPerRow * 21 ) + 5 , [ hexScroll frame ] . size . height ) ] ;
[ asciiScroll setFrameOrigin : NSMakePoint ( ( bytesPerRow * 21 ) + 95 , 20 ) ] ;
[ asciiScroll setFrameSize : NSMakeSize ( ( bytesPerRow * 7 ) + 28 , [ asciiScroll frame ] . size . height ) ] ;
}
2002-11-13 03:35:54 +00:00
- ( void ) windowDidBecomeKey : ( NSNotification * ) notification
{
// swap paste : menu item for my own paste submenu
NSMenu * editMenu = [ [ [ NSApp mainMenu ] itemAtIndex : 2 ] submenu ] ;
NSMenuItem * pasteItem = [ editMenu itemAtIndex : [ editMenu indexOfItemWithTarget : nil andAction : @ selector ( paste : ) ] ] ;
[ NSBundle loadNibNamed : @ "PasteMenu" owner : self ] ;
[ pasteItem setEnabled : YES ] ;
[ pasteItem setKeyEquivalent : @ "\0" ] ; // clear key equiv . ( yes , really ! )
[ pasteItem setKeyEquivalentModifierMask : 0 ] ;
[ editMenu setSubmenu : pasteSubmenu forItem : pasteItem ] ;
}
- ( void ) windowDidResignKey : ( NSNotification * ) notification
{
// swap my submenu for plain paste menu item
NSMenu * editMenu = [ [ [ NSApp mainMenu ] itemAtIndex : 2 ] submenu ] ;
NSMenuItem * pasteItem = [ editMenu itemAtIndex : [ editMenu indexOfItemWithSubmenu : pasteSubmenu ] ] ;
[ editMenu setSubmenu : nil forItem : pasteItem ] ;
[ pasteItem setTarget : nil ] ;
[ pasteItem setAction : @ selector ( paste : ) ] ;
[ pasteItem setKeyEquivalent : @ "v" ] ;
[ pasteItem setKeyEquivalentModifierMask : NSCommandKeyMask ] ;
}
2002-12-31 19:06:40 +00:00
- ( BOOL ) windowShouldClose : ( id ) sender
{
if ( [ [ self window ] isDocumentEdited ] )
{
NSBeginAlertSheet ( @ "Do you want to save the changes you made to this resource?" , @ "Save" , @ "Don<6F> 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
2002-05-31 00:17:53 +00:00
{
2002-12-31 19:06:40 +00:00
[ resource setData : [ backup data ] ] ;
}
2002-02-06 20:57:56 +00:00
2002-03-21 04:02:26 +00:00
- ( IBAction ) showFind : ( id ) sender
{
// bug : HexWindowController allocs a sheet controller , but it ' s never disposed of
FindSheetController * sheetController = [ [ FindSheetController alloc ] initWithWindowNibName : @ "FindSheet" ] ;
[ sheetController showFindSheet : self ] ;
}
2002-02-11 22:03:20 +00:00
- ( void ) viewDidScroll : ( NSNotification * ) notification
{
// get object refs for increased speed
NSClipView * object = ( NSClipView * ) [ notification object ] ;
NSClipView * offsetClip = [ [ offset enclosingScrollView ] contentView ] ;
NSClipView * hexClip = [ [ hex enclosingScrollView ] contentView ] ;
NSClipView * asciiClip = [ [ ascii enclosingScrollView ] contentView ] ;
// due to a bug in - [ NSView setPostsBoundsChangedNotifications : ] ( it basically doesn ' t work ) , I am having to work around it by removing myself from the notification center and restoring things later on !
2002-12-31 19:06:40 +00:00
// update , Apple say this isn ' t their bug . Yeah , right !
2002-02-11 22:03:20 +00:00
[ [ NSNotificationCenter defaultCenter ] removeObserver : self name : NSViewBoundsDidChangeNotification object : nil ] ;
// when a view scrolls , update the other two
if ( object ! = offsetClip )
{
// [ offsetClip setPostsBoundsChangedNotifications : NO ] ;
[ offsetClip setBoundsOrigin : [ object bounds ] . origin ] ;
// [ offsetClip setPostsBoundsChangedNotifications : YES ] ;
}
if ( object ! = hexClip )
{
// [ hexClip setPostsBoundsChangedNotifications : NO ] ;
[ hexClip setBoundsOrigin : [ object bounds ] . origin ] ;
// [ hexClip setPostsBoundsChangedNotifications : YES ] ;
}
if ( object ! = asciiClip )
{
// [ asciiClip setPostsBoundsChangedNotifications : NO ] ;
[ asciiClip setBoundsOrigin : [ object bounds ] . origin ] ;
// [ asciiClip setPostsBoundsChangedNotifications : YES ] ;
}
// restore notifications
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( viewDidScroll : ) name : NSViewBoundsDidChangeNotification object : offsetClip ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( viewDidScroll : ) name : NSViewBoundsDidChangeNotification object : hexClip ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( viewDidScroll : ) name : NSViewBoundsDidChangeNotification object : asciiClip ] ;
}
2002-04-30 23:44:23 +00:00
- ( void ) resourceNameDidChange : ( NSNotification * ) notification
{
2003-08-05 04:08:19 +00:00
[ [ self window ] setTitle : [ ( id < ResKnifeResourceProtocol > ) [ notification object ] nameForEditorWindow ] ] ;
2002-04-30 23:44:23 +00:00
}
2002-02-14 23:24:53 +00:00
- ( void ) resourceDataDidChange : ( NSNotification * ) notification
2002-02-12 01:24:53 +00:00
{
2002-02-14 23:24:53 +00:00
// ensure it ' s our resource which got changed ( should always be true , we don ' t register for other resource notifications )
2002-02-23 03:40:24 +00:00
if ( [ notification object ] = = ( id ) resource )
2002-12-31 19:06:40 +00:00
{
2002-02-23 03:40:24 +00:00
[ self refreshData : [ resource data ] ] ;
2002-12-31 19:06:40 +00:00
[ 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 ] ;
}
2002-02-12 01:24:53 +00:00
}
2002-02-02 11:48:54 +00:00
- ( void ) refreshData : ( NSData * ) data ;
{
2002-03-21 04:02:26 +00:00
NSDictionary * dictionary ;
NSMutableParagraphStyle * paragraph = [ [ NSParagraphStyle defaultParagraphStyle ] mutableCopy ] ;
2002-02-23 03:40:24 +00:00
// save selections
NSRange hexSelection = [ hex selectedRange ] ;
NSRange asciiSelection = [ ascii selectedRange ] ;
2002-02-06 20:57:56 +00:00
// clear delegates ( see HexEditorDelegate class for explanation of why )
2002-02-02 11:48:54 +00:00
id oldDelegate = [ hex delegate ] ;
[ hex setDelegate : nil ] ;
[ ascii setDelegate : nil ] ;
2002-03-21 04:02:26 +00:00
// prepare attributes dictionary
[ paragraph setLineBreakMode : NSLineBreakByCharWrapping ] ;
dictionary = [ NSDictionary dictionaryWithObject : paragraph forKey : NSParagraphStyleAttributeName ] ;
2002-02-02 11:48:54 +00:00
// do stuff with data
[ offset setString : [ hexDelegate offsetRepresentation : data ] ] ;
[ hex setString : [ hexDelegate hexRepresentation : data ] ] ;
[ ascii setString : [ hexDelegate asciiRepresentation : data ] ] ;
2002-03-21 04:02:26 +00:00
// apply attributes
[ [ offset textStorage ] addAttributes : dictionary range : NSMakeRange ( 0 , [ [ offset textStorage ] length ] ) ] ;
[ [ hex textStorage ] addAttributes : dictionary range : NSMakeRange ( 0 , [ [ hex textStorage ] length ] ) ] ;
[ [ ascii textStorage ] addAttributes : dictionary range : NSMakeRange ( 0 , [ [ ascii textStorage ] length ] ) ] ;
2002-02-23 03:40:24 +00:00
// restore selections ( this is the dumbest way to do it , but it ' ll do for now )
2002-04-27 18:17:47 +00:00
[ hex setSelectedRange : NSIntersectionRange ( hexSelection , [ hex selectedRange ] ) ] ;
[ ascii setSelectedRange : NSIntersectionRange ( asciiSelection , [ ascii selectedRange ] ) ] ;
2002-02-23 03:40:24 +00:00
2002-02-02 11:48:54 +00:00
// restore delegates
[ hex setDelegate : oldDelegate ] ;
[ ascii setDelegate : oldDelegate ] ;
}
2002-02-06 20:57:56 +00:00
- ( id ) resource
{
return resource ;
}
- ( NSData * ) data
{
2002-02-23 03:40:24 +00:00
return [ resource data ] ;
2002-02-06 20:57:56 +00:00
}
2002-03-21 04:02:26 +00:00
- ( int ) bytesPerRow
{
return bytesPerRow ;
}
2002-11-13 03:35:54 +00:00
- ( NSMenu * ) pasteSubmenu
{
return pasteSubmenu ;
}
2002-05-09 23:29:22 +00:00
- ( NSUndoManager * ) windowWillReturnUndoManager : ( NSWindow * ) sender
{
2002-05-31 00:17:53 +00:00
return undoManager ;
2002-05-09 23:29:22 +00:00
}
2002-04-27 18:17:47 +00:00
@ end