229 lines
7.9 KiB
Objective-C
229 lines
7.9 KiB
Objective-C
/*
|
|
* PDP-8/E Simulator
|
|
*
|
|
* Copyright © 1994-2015 Bernhard Baehr
|
|
*
|
|
* BreakpointController.m - Class for maintaining breakpoints
|
|
*
|
|
* This file is part of PDP-8/E Simulator.
|
|
*
|
|
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
|
#import "BreakpointController.h"
|
|
#import "BreakpointArray.h"
|
|
#import "OctalFormatter.h"
|
|
#import "Utilities.h"
|
|
|
|
|
|
@implementation BreakpointController
|
|
|
|
|
|
/* ADDRESS_COLUMN is the identifier of the address column. The other checkbox
|
|
columns must be identified with integers representing the bit mask for the
|
|
enabled bit in the breakpoints enable bit mask, i. e. 1, 2, 4, 8,...
|
|
Then ALL_BREAKPOINTS is the mask for "all columns enabled". */
|
|
|
|
#define ADDRESS_COLUMN 0
|
|
#define ALL_BREAKPOINTS ((1 << ([tableView numberOfColumns] - 1)) - 1)
|
|
|
|
|
|
/* #defines for the cases where the instance must know if it is the
|
|
breakpoints or break opcodes controller */
|
|
|
|
#define IS_BREAKPOINT_CONTROLLER ([tableView numberOfColumns] == 2)
|
|
#define IS_BREAKOPCODE_CONTROLLER ([tableView numberOfColumns] == 3)
|
|
|
|
#define MAX_ADDRESS (IS_BREAKPOINT_CONTROLLER ? 077777 : 07777)
|
|
|
|
#define BREAKPOINT_COLUMN 1
|
|
#define USER_BREAKOPCODE_COLUMN 1
|
|
#define SYSTEM_BREAKOPCODE_COLUMN 2
|
|
|
|
|
|
- (void) notifyUpdateBreakpointView:(NSNotification *)notification
|
|
{
|
|
// NSLog (@"BreakpointController notifyUpdateBreakpointView");
|
|
[enableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:ALL_BREAKPOINTS]];
|
|
[disableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:0]];
|
|
[tableView reloadData];
|
|
}
|
|
|
|
|
|
- (IBAction) addBreakpoint:(id)sender
|
|
{
|
|
[[sender window] makeKeyWindow];
|
|
[breakpoints setBreakpointWithIdentifier:0 value:ALL_BREAKPOINTS];
|
|
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
|
[tableView editColumn:[tableView columnWithIdentifier:
|
|
[NSString stringWithFormat:@"%d", ADDRESS_COLUMN]]
|
|
row:0 withEvent:nil select:YES];
|
|
}
|
|
|
|
|
|
- (IBAction) deleteBreakpoint:(id)sender
|
|
{
|
|
int selectedRow = [tableView selectedRow];
|
|
[tableView reloadData]; // when editing, this saves the edited cell that will be deleted
|
|
[breakpoints deleteBreakpointsAtIndexes:[tableView selectedRowIndexes]];
|
|
// reselect old row, otherwise selection jumps to the position of the edited but deleted breakpoint
|
|
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] byExtendingSelection:NO];
|
|
}
|
|
|
|
|
|
- (IBAction) enableAllBreakpoints:(id)sender
|
|
{
|
|
[breakpoints setAllValues:ALL_BREAKPOINTS];
|
|
}
|
|
|
|
|
|
- (IBAction) disableAllBreakpoints:(id)sender
|
|
{
|
|
[breakpoints setAllValues:0];
|
|
}
|
|
|
|
|
|
- (void) tableViewSelectionDidChange:(NSNotification *)notification
|
|
{
|
|
[deleteButton setEnabled:[tableView numberOfSelectedRows] != 0];
|
|
}
|
|
|
|
|
|
- (int) numberOfRowsInTableView:(NSTableView *)tableView
|
|
{
|
|
return [breakpoints numberOfBreakpoints];
|
|
}
|
|
|
|
|
|
- (id) tableView:(NSTableView *)tableView
|
|
objectValueForTableColumn:(NSTableColumn *)column row:(int)row
|
|
{
|
|
int columnID = [[column identifier] intValue];
|
|
return columnID == ADDRESS_COLUMN ?
|
|
[NSNumber numberWithInt:[breakpoints identifierAtIndex:row]] :
|
|
[NSNumber numberWithBool:[breakpoints valueAtIndex:row] & columnID];
|
|
}
|
|
|
|
|
|
- (void) tableView:(NSTableView *)tabView setObjectValue:(id)object
|
|
forTableColumn:(NSTableColumn *)column row:(int)row
|
|
{
|
|
int columnID = [[column identifier] intValue];
|
|
if (columnID == ADDRESS_COLUMN) {
|
|
[breakpoints deleteBreakpointAtIndex:row];
|
|
if ([object isKindOfClass:[NSNumber class]])
|
|
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:
|
|
[breakpoints setBreakpointWithIdentifier:[object intValue]
|
|
value:ALL_BREAKPOINTS]]
|
|
byExtendingSelection:NO];
|
|
else {
|
|
NSIndexSet *index = [breakpoints setBreakpointsWithIdentifierArray:object
|
|
value:ALL_BREAKPOINTS];
|
|
[tableView selectRowIndexes:index byExtendingSelection:NO];
|
|
row = [index firstIndex];
|
|
}
|
|
[tableView editColumn:0 row:0 withEvent:nil select:NO];
|
|
// [tableView abortEditing] does not work, so edit an invalid cell
|
|
[tableView scrollRowToVisible:row];
|
|
[tableView reloadData];
|
|
[enableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:ALL_BREAKPOINTS]];
|
|
[disableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:0]];
|
|
} else {
|
|
unsigned value = [breakpoints valueAtIndex:row];
|
|
if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
|
|
value = value ? 0 : ALL_BREAKPOINTS;
|
|
else
|
|
value = (value & columnID) ? (value & ~columnID) : (value | columnID);
|
|
[breakpoints setBreakpointWithIdentifier:[breakpoints identifierAtIndex:row] value:value];
|
|
}
|
|
}
|
|
|
|
|
|
- (NSString *) tableView:(NSTableView *)tabView toolTipForCell:(NSCell *)cell
|
|
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)column row:(int)row
|
|
mouseLocation:(NSPoint)mouseLocation
|
|
{
|
|
switch ([[column identifier] intValue]) {
|
|
case ADDRESS_COLUMN :
|
|
return IS_BREAKPOINT_CONTROLLER ?
|
|
NSLocalizedString(
|
|
@"Address where the PDP-8 halts when the breakpoint is enabled", @"") :
|
|
NSLocalizedString(
|
|
@"Opcode that causes the PDP-8 to halt when enabled for the current mode", @"");
|
|
case BREAKPOINT_COLUMN | USER_BREAKOPCODE_COLUMN :
|
|
return IS_BREAKPOINT_CONTROLLER ?
|
|
NSLocalizedString(@"Enables or disables this breakpoint", @"") :
|
|
NSLocalizedString(@"Enables or disables this break opcode for PDP-8 user mode "
|
|
@"(option-click to set user and system mode simultaneously)", @"");
|
|
case SYSTEM_BREAKOPCODE_COLUMN :
|
|
return NSLocalizedString(@"Enables or disables this break opcode for PDP-8 system mode "
|
|
@"(option-click to set user and system mode simultaneously)", @"");
|
|
|
|
default :
|
|
NSAssert (FALSE, @"Unknown column in BreakpointControllers table view");
|
|
break;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
|
|
- (BOOL) control:(NSControl *)control didFailToFormatString:(NSString *)string
|
|
errorDescription:(NSString *)error
|
|
{
|
|
[control abortEditing];
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
|
[alert setMessageText:error];
|
|
[alert beginSheetModalForWindow:[control window] modalDelegate:self
|
|
didEndSelector:nil contextInfo:nil];
|
|
[alert release];
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (void) awakeFromNib
|
|
{
|
|
NSCell *dataCell = [[tableView tableColumnWithIdentifier:
|
|
[NSString stringWithFormat:@"%d", ADDRESS_COLUMN]] dataCell];
|
|
[dataCell setFormatter:[OctalFormatter formatterWithBitMask:MAX_ADDRESS wildcardAllowed:YES]];
|
|
[dataCell setFont:[NSFont userFixedPitchFontOfSize:11]];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(notifyUpdateBreakpointView:)
|
|
name:BREAKPOINTS_CHANGED_NOTIFICATION object:breakpoints];
|
|
/* set max width = min width of the panel: IB only allows max width one pixel more
|
|
than min width, so the user can resize the width for one pixel - bug in IB? */
|
|
NSSize size = [[tableView window] minSize];
|
|
size.height = [[tableView window] maxSize].height;
|
|
[[tableView window] setMaxSize:size];
|
|
if (runningOnLionOrNewer()) { // move the + and - button title one pixel up
|
|
NSMutableParagraphStyle *style= [[[NSMutableParagraphStyle alloc] init] autorelease];
|
|
[style setAlignment:NSCenterTextAlignment];
|
|
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
[NSNumber numberWithFloat:1], NSBaselineOffsetAttributeName,
|
|
style, NSParagraphStyleAttributeName, nil];
|
|
[addButton setAttributedTitle:
|
|
[[[NSAttributedString alloc] initWithString:[addButton title] attributes:dict] autorelease]];
|
|
[deleteButton setAttributedTitle:
|
|
[[[NSAttributedString alloc] initWithString:[deleteButton title] attributes:dict] autorelease]];
|
|
}
|
|
adjustTableHeaderForElCapitan (tableView);
|
|
}
|
|
|
|
|
|
@end
|
|
|
|
|