/* * PDP-8/E Simulator * * Copyright © 1994-2015 Bernhard Baehr * * PaperTapeController.m - Controller for a paper tape reader and punch * * 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 . */ #import #import "FileDropControlTargetProtocol.h" #import "PaperTapeController.h" #import "NSControl+FileDrop.h" #import "NSThread+MainThread.h" #import "Utilities.h" #import "EnableDisableTextField.h" #import "Unicode.h" #import "InputConsumerProtocol.h" #import "PaperTapeProgressIndicator.h" @implementation PaperTapeController #define PAPER_TAPE_ON_TAG 0 #define PAPER_TAPE_OFF_TAG 1 #define PAPER_TAPE_READER 0 #define PAPER_TAPE_PUNCH 1 - (void) setEnabled:(BOOL)flag { [loadUnloadButton setEnabled:flag]; [filenameField setEnabled:flag]; if (onOffButton) [onOffButton setEnabled:flag && fileHandle != nil]; } - (int) getChar { NSAssert (kind == PAPER_TAPE_READER, @"Cannot read from paper tape punch"); int c = EOF; if (fileHandle) { if (onOffButton == nil || [onOffButton selectedSegment] == PAPER_TAPE_ON_TAG) { NSData *data = [fileHandle readDataOfLength:1]; if ([data length] == 1) { c = * (unsigned char *) [data bytes]; if ([NSThread isMainThread]) [progressIndicator incrementAndAnimate]; else [progressIndicator performSelectorOnMainThread:@selector(incrementAndAnimate) withObject:self waitUntilDone:NO]; } else { if ([NSThread isMainThread]) [self loadUnloadClicked:self]; else [self performSelectorOnMainThread:@selector(loadUnloadClicked:) withObject:self waitUntilDone:NO]; } } } return c; } - (BOOL) putChar:(unsigned char)c handleBackspace:(BOOL)handleBackspace { NSAssert (kind == PAPER_TAPE_PUNCH, @"Cannot punch to paper tape reader"); BOOL done = NO; if (fileHandle && (onOffButton == nil || [onOffButton selectedSegment] == PAPER_TAPE_ON_TAG)) { if (c == '\b' && handleBackspace) { long size = (long) [fileHandle offsetInFile]; if (size > 0) [fileHandle truncateFileAtOffset:size - 1]; } else [fileHandle writeData:[NSData dataWithBytes:&c length:1]]; if ([NSThread isMainThread]) [progressIndicator incrementAndAnimate]; else [progressIndicator performSelectorOnMainThread:@selector(incrementAndAnimate) withObject:self waitUntilDone:NO]; done = YES; } return done; } - (void) mountFile:(NSFileHandle *)handle withPath:(NSString *)path { fileHandle = handle; [fileHandle retain]; [fileHandle seekToEndOfFile]; unsigned long long offset = [fileHandle offsetInFile]; [fileHandle seekToFileOffset:0]; [progressIndicator setMaxValue:offset]; [progressIndicator setDoubleValue:0]; NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *title = NSLocalizedStringFromTableInBundle(@"Unload", nil, bundle, @""); if ([loadUnloadButton class] == [NSSegmentedControl class]) [(NSSegmentedControl *) loadUnloadButton setLabel:title forSegment:0]; else [(NSButton *) loadUnloadButton setTitle:title]; [loadUnloadButton unregisterAsFileDropTarget]; if (onOffButton) [onOffButton setEnabled:YES]; [filenameField setStringValue:[[NSFileManager defaultManager] displayNameAtPath:path]]; [filenameField setHidden:NO]; [progressIndicator setHidden:NO]; } - (void) panelDidEnd:(NSSavePanel *)panel return:(int)ret context:(void *)context { NSFileHandle *handle; if (ret == NSOKButton) { NSString *path = [panel filename]; if (kind == PAPER_TAPE_READER) handle = [NSFileHandle fileHandleForReadingAtPath:path]; else { [[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil]; handle = [NSFileHandle fileHandleForWritingAtPath:path]; } if (handle) [self mountFile:handle withPath:path]; else { [panel close]; NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:(kind == PAPER_TAPE_READER) ? NSLocalizedStringFromTableInBundle( @"Cannot open this paper tape file.", nil, bundle, @"") : NSLocalizedStringFromTableInBundle( @"Cannot create this paper tape file.", nil, bundle, @"")]; [alert setInformativeText:path]; [alert beginSheetModalForWindow:[loadUnloadButton window] modalDelegate:nil didEndSelector:nil contextInfo:nil]; [alert release]; } } [[NSUserDefaults standardUserDefaults] setObject:[panel directory] forKey:LAST_FILE_PANEL_DIR_KEY]; } - (IBAction) loadUnloadClicked:(id)sender { if (fileHandle) { [fileHandle closeFile]; [fileHandle release]; fileHandle = nil; NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *title = NSLocalizedStringFromTableInBundle(@"Load", nil, bundle, @""); if ([loadUnloadButton class] == [NSSegmentedControl class]) [(NSSegmentedControl *) loadUnloadButton setLabel:title forSegment:0]; else [(NSButton *) loadUnloadButton setTitle:title]; [loadUnloadButton setEnabled:onOffButton == nil ||[onOffButton isEnabled]]; [loadUnloadButton registerAsFileDropTarget]; if (onOffButton) { [onOffButton setEnabled:NO]; [onOffButton selectSegmentWithTag:PAPER_TAPE_OFF_TAG]; } [filenameField setHidden:YES]; [progressIndicator setHidden:YES]; } else { NSSavePanel *panel = (kind == PAPER_TAPE_READER) ? [NSOpenPanel openPanel] : [NSSavePanel savePanel]; [panel beginSheetForDirectory: [[NSUserDefaults standardUserDefaults] stringForKey:LAST_FILE_PANEL_DIR_KEY] file:nil modalForWindow:[loadUnloadButton window] modalDelegate:self didEndSelector:@selector(panelDidEnd:return:context:) contextInfo:nil]; } } - (IBAction) onOffClicked:(id)sender { if ([onOffButton selectedSegment] == PAPER_TAPE_ON_TAG) { [loadUnloadButton setEnabled:NO]; if (kind == PAPER_TAPE_READER) [inputConsumer canContinueInput]; } else { [loadUnloadButton setEnabled:YES]; [progressIndicator stopAnimation:sender]; } } - (void) awakeFromNib { kind = [loadUnloadButton tag]; adjustToolbarControlForTiger (filenameField); adjustToolbarControlForTiger (progressIndicator); [loadUnloadButton registerAsFileDropTarget]; } #pragma mark FileDropControlTarget Protocol - (BOOL) willAcceptFile:(NSString *)path { NSFileHandle *handle = (kind == PAPER_TAPE_READER) ? [NSFileHandle fileHandleForReadingAtPath:path] : [NSFileHandle fileHandleForWritingAtPath:path]; if (handle) { [handle closeFile]; // [handle release]; // dont'd release, it crashs } return handle != nil; } - (BOOL) acceptFile:(NSString *)path { NSFileHandle *handle = nil; if (kind == PAPER_TAPE_PUNCH) { NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle( @"Do you really want to overwrite %C%@%C with the paper tape output?", nil, bundle, @""), UNICODE_LEFT_DOUBLEQUOTE, [[NSFileManager defaultManager] displayNameAtPath:path], UNICODE_RIGHT_DOUBLEQUOTE]]; [alert setInformativeText:NSLocalizedStringFromTableInBundle( @"The current content of the file will be lost.", nil, bundle, @"")]; [[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle( @"Yes", nil, bundle, @"")] setKeyEquivalent:@"\r"]; [[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle( @"No", nil, bundle, @"")] setKeyEquivalent:@"\e"]; [alert setAlertStyle:NSCriticalAlertStyle]; if ([alert runModal] == NSAlertFirstButtonReturn && (handle = [NSFileHandle fileHandleForWritingAtPath:path])) [handle truncateFileAtOffset:0]; [alert release]; } else handle = [NSFileHandle fileHandleForReadingAtPath:path]; if (handle) [self mountFile:handle withPath:path]; return handle != nil; } @end