// // EMController.m // EdenMath // // Created by admin on Thu Feb 21 2002. // Copyright (c) 2002-2004 Edenwaith. All rights reserved. // #import "EMController.h" @implementation EMController // ------------------------------------------------------- // (id)init // Allocate memory and french fries for EdenMath // ------------------------------------------------------- - (id)init { em = [[EMResponder alloc] init]; undoManager = [[NSUndoManager alloc] init]; return self; } // ------------------------------------------------------- // (void)dealloc // Deallocate/free up memory used by Edenmath // ------------------------------------------------------- - (void)dealloc { [em release]; [undoManager release]; [super dealloc]; } // ------------------------------------------------------- // (void) awakeFromNib // ------------------------------------------------------- - (void)awakeFromNib { [[displayField window] makeKeyAndOrderFront:self]; } // ------------------------------------------------------- // (void) off:(id)sender // When the Off button is pressed, the application is // terminated // ------------------------------------------------------- - (void)off:(id)sender { [NSApp terminate:self]; } // ------------------------------------------------------- // (void) clear:(id)sender // ------------------------------------------------------- - (void)clear:(id)sender { [self saveState]; [em clear]; [self updateDisplay]; } // ------------------------------------------------------- // (void) cut:(id)sender // ------------------------------------------------------- - (void)cut:(id)sender { [self copy:sender]; [self saveState]; [self clear:self]; } // ------------------------------------------------------- // (void) copy:(id)sender // ------------------------------------------------------- - (void)copy:(id)sender { NSString *contents = [displayField stringValue]; NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; [pasteboard setString:contents forType:NSStringPboardType]; } // ------------------------------------------------------- // (void) paste:(id)sender // ------------------------------------------------------- - (void)paste:(id)sender { NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; NSString *type = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]; if (type != nil) { NSString *contents = [pasteboard stringForType:type]; if (contents != nil) { NSScanner *scanner = [NSScanner scannerWithString:contents]; double value; if ([scanner scanDouble:&value]) { [self saveState]; [em setCurrentValue:value]; [self updateDisplay]; } } } } // ------------------------------------------------------- // (void) updateDisplay:(id)sender // Update the value in the display field on the // calculator. In versions 1.0.0 and 1.0.1, this was // a 1 line method. Because of odd precision problems and // numbers like 0.001 not showing the 0's as they are // typed has required the extra 50 (or so) lines of code // ------------------------------------------------------- - (void)updateDisplay { double current_value = [em getCurrentValue]; char *y = "%15."; int i = [em getTrailingDigits]; char *z = "f"; char c_string[32] = ""; NSString *true_precision = [[NSString alloc] initWithFormat: @"%s%d%s", y, i-1, z]; NSString *new_string; // = [[NSString alloc] init]; // variables for the new algorithm to format numbers properly and eliminate unncessary // '0' from the end of a final number. char final_string[32] = ""; int cs_len = 0; int j = 0; int decimal_places = 0; BOOL is_decimal = NO; // 0 is false, 1 is true BOOL is_zero = YES; // is true int new_len = 0; int num_zeros = 0; NSString *precision = @"%15.10f"; // default precision NSString *string_value = [NSString stringWithFormat:precision, current_value]; // convert to string with certain string format if (i != 0) // if there ARE some set trailing digits like 65.2 or 0.001 { NSString *other_value = [NSString stringWithFormat:true_precision, current_value]; [displayField setStringValue: other_value]; } else // no trailing_digits because it is a number like 6 or it is an answer and // trailing_digits was reset to 0 { // loop through the string converted version of the current_value, and cut // off any excess 0's at the end of the number, so 63.20 will appear like 63.2 current_value = [string_value doubleValue]; [string_value getCString: c_string]; // new algorithm for formating numbers properly on output // check to see if there is a decimal place, and if so, how many // decimal places exist cs_len = strlen(c_string); for (j = 0; j < cs_len; j++) { if (c_string[j] == '.') { is_decimal = YES; while (j < cs_len) { j++; decimal_places++; } } } // if a decimal place exists, go through to get rid of unnecessary 0's at // the end of the number so 65.20 will appear to be 65.2 if (is_decimal == YES) { for (j = 0; (j < decimal_places) && (is_zero == YES); j++) { new_len = cs_len - (1 + j); // count the number of 0's at the end if (c_string[new_len] == '0') { num_zeros++; } else if (c_string[new_len] == '.') { num_zeros++; is_zero = NO; } else // otherwise, no more excess 0's to be found { is_zero = NO; } } // loop through the necessary number of times to get rid of // unneeded 0's for (j = 0; j < (cs_len - num_zeros); j++) { final_string[j] = c_string[j]; } } else // otherwise, there is no decimal place { strcpy(final_string, c_string); } new_string = [NSString stringWithFormat:@"%s", final_string]; // When printing out to NSLog, new_string looks odd (\\304\\026\\010\\304), // but when placed as a parameter, it seems to work. Go figure. [displayField setStringValue: new_string]; } } // ------------------------------------------------------- // (BOOL) applicationShould....:(NSApplication *)theApplication // Terminate the program when the last window closes // Need to connect File Owner and Window to EMController // for this to work correctly // ------------------------------------------------------- - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication { return YES; } // ------------------------------------------------------- // (void) saveState // ------------------------------------------------------- - (void)saveState { [undoManager registerUndoWithTarget:self selector:@selector(setState:) object:[em state]]; } // ------------------------------------------------------- // (void) setState // ------------------------------------------------------- - (void)setState:(NSDictionary *)emState { [self saveState]; [em setState:emState]; [self updateDisplay]; } // ------------------------------------------------------- // (void) undoAction // ------------------------------------------------------- - (void)undoAction:(id)sender { if ([undoManager canUndo]) { [undoManager undo]; } } // ------------------------------------------------------- // (NSUndoManager *) windowWillReturnUndoManager:(NSWindow *)sender // ------------------------------------------------------- - (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)sender { return undoManager; } // ------------------------------------------------------- // (IBAction) checkForNewVersion: (id) sender // ------------------------------------------------------- // Version: 8. May 2004 23:55 // Created: 8. May 2004 23:55 // ------------------------------------------------------- - (IBAction) checkForNewVersion: (id) sender { NSString *currentVersionNumber = [[[NSBundle bundleForClass:[self class]] infoDictionary] objectForKey:@"CFBundleVersion"]; NSDictionary *productVersionDict = [NSDictionary dictionaryWithContentsOfURL: [NSURL URLWithString:@"http://www.edenwaith.com/version.xml"]]; NSString *latestVersionNumber = [productVersionDict valueForKey:@"EdenMath"]; int button = 0; if ( latestVersionNumber == nil ) { NSBeep(); NSRunAlertPanel(@"Could not check for update", @"A problem arose while attempting to check for a new version of EdenMath. Edenwaith.com may be temporarily unavailable or your network may be down.", @"OK", nil, nil); } else if ( [latestVersionNumber isEqualTo: currentVersionNumber] ) { NSRunAlertPanel(@"Software is Up-To-Date", @"You have the most recent version of EdenMath.", @"OK", nil, nil); } else { button = NSRunAlertPanel(@"New Version is Available", @"A new version of EdenMath is available.", @"OK", @"Cancel", nil); if (NSOKButton == button) { [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:@"http://www.edenwaith.com/downloads/edenmath.php"]]; } } } // ------------------------------------------------------- // (IBAction) goToProductPage: (id) sender // ------------------------------------------------------- // Version: 8. May 2004 23:55 // Created: 8. May 2004 23:55 // ------------------------------------------------------- - (IBAction) goToProductPage: (id) sender { [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:@"http://www.edenwaith.com/products/edenmath/"]]; } // ------------------------------------------------------- // (IBAction) goToFeedbackPage: (id) sender // ------------------------------------------------------- // Version: 8. May 2004 23:55 // Created: 8. May 2004 23:55 // ------------------------------------------------------- - (IBAction) goToFeedbackPage: (id) sender { [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:@"http://www.edenwaith.com/support/feedback.php?app=EdenMath"]]; } // ===================================================================================== // CONSTANTS // ===================================================================================== // ------------------------------------------------------- // (void) digitButton:(id)sender // New addition to EM 1.1.1 which eliminates ten other // functions (zeroButton...nineButton) so each number // button does not explicitly need to point to a new // function. // ------------------------------------------------------- - (void) digitButton: (id) sender { [self saveState]; [em newDigit: [[sender title] intValue]]; [self updateDisplay]; } // ------------------------------------------------------- // (void) period:(id)sender // ------------------------------------------------------- - (void)period:(id)sender { [self saveState]; [em period]; [self updateDisplay]; } // ------------------------------------------------------- // (void) pi2:(id)sender // ------------------------------------------------------- - (void)pi2:(id)sender { [self saveState]; [em trig_constant:2*M_PI]; [self updateDisplay]; } // ------------------------------------------------------- // (void) pi3_2:(id)sender // ------------------------------------------------------- - (void)pi3_2:(id)sender { [self saveState]; [em trig_constant:3*M_PI/2]; [self updateDisplay]; } // ------------------------------------------------------- // (void) pi:(id)sender // ------------------------------------------------------- - (void)pi:(id)sender { [self saveState]; [em pi]; [self updateDisplay]; } // ------------------------------------------------------- // (void) pi_2:(id)sender // ------------------------------------------------------- - (void)pi_2:(id)sender { [self saveState]; [em trig_constant:M_PI/2]; [self updateDisplay]; } // ------------------------------------------------------- // (void) pi_3:(id)sender // ------------------------------------------------------- - (void)pi_3:(id)sender { [self saveState]; [em trig_constant:M_PI/3]; [self updateDisplay]; } // ------------------------------------------------------- // (void) pi_4:(id)sender // ------------------------------------------------------- - (void)pi_4:(id)sender { [self saveState]; [em trig_constant:M_PI/4]; [self updateDisplay]; } // ------------------------------------------------------- // (void) pi_6:(id)sender // ------------------------------------------------------- - (void)pi_6:(id)sender { [self saveState]; [em trig_constant:M_PI/6]; [self updateDisplay]; } // ------------------------------------------------------- // (void) e:(id)sender // ------------------------------------------------------- - (void)e:(id)sender { [self saveState]; [em e]; [self updateDisplay]; } // ===================================================================================== // STANDARD FUNCTIONS // ===================================================================================== // ------------------------------------------------------- // (void) enter:(id)sender // ------------------------------------------------------- - (void)enter:(id)sender { [self saveState]; [em enter]; [self updateDisplay]; } // ------------------------------------------------------- // (void) add:(id)sender // ------------------------------------------------------- - (void)add:(id)sender { [self saveState]; [em operation:ADD_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) subtract:(id)sender // ------------------------------------------------------- - (void)subtract:(id)sender { [self saveState]; [em operation:SUBTRACT_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) multiply:(id)sender // ------------------------------------------------------- - (void)multiply:(id)sender { [self saveState]; [em operation:MULTIPLY_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) divide:(id)sender // ------------------------------------------------------- - (void)divide:(id)sender { [self saveState]; [em operation:DIVIDE_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) reverse_sign:(id)sender // ------------------------------------------------------- - (void)reverse_sign:(id)sender { [self saveState]; [em reverse_sign]; [self updateDisplay]; } // ------------------------------------------------------- // (void) percentage:(id)sender // ------------------------------------------------------- - (void)percentage:(id)sender { [self saveState]; [em percentage]; [self updateDisplay]; } // ------------------------------------------------------- // (void) mod:(id)sender // ------------------------------------------------------- - (void)mod:(id)sender { [self saveState]; [em operation:MOD_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) EE:(id)sender // ------------------------------------------------------- - (void)EE:(id)sender { [self saveState]; [em operation:EE_OP]; [self updateDisplay]; } // ===================================================================================== // ALGEBRAIC FUNCTIONS // ===================================================================================== // ------------------------------------------------------- // (void) exponent:(id)sender // x^2 // ------------------------------------------------------- - (void)squared:(id)sender { [self saveState]; [em squared]; [self updateDisplay]; } // ------------------------------------------------------- // (void) cubed:(id)sender // x^2 // ------------------------------------------------------- - (void)cubed:(id)sender { [self saveState]; [em cubed]; [self updateDisplay]; } // ------------------------------------------------------- // (void) exponent:(id)sender // x^y // ------------------------------------------------------- - (void)exponent:(id)sender { [self saveState]; [em operation:EXPONENT_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) xroot:(id)sender // Ã // ------------------------------------------------------- - (void)square_root:(id)sender { [self saveState]; [em square_root]; [self updateDisplay]; } // ------------------------------------------------------- // (void) xroot:(id)sender // 3Ã // ------------------------------------------------------- - (void)cubed_root:(id)sender { [self saveState]; [em cubed_root]; [self updateDisplay]; } // ------------------------------------------------------- // (void) xroot:(id)sender // yÃx // ------------------------------------------------------- - (void)xroot:(id)sender { [self saveState]; [em operation:XROOT_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) ln:(id)sender // ------------------------------------------------------- - (void)ln:(id)sender { [self saveState]; [em ln]; [self updateDisplay]; } // ------------------------------------------------------- // (void) logarithm:(id)sender // ------------------------------------------------------- - (void)logarithm:(id)sender { [self saveState]; [em logarithm]; [self updateDisplay]; } // ------------------------------------------------------- // (void) factorial:(id)sender // ------------------------------------------------------- - (void)factorial:(id)sender { [self saveState]; [em factorial]; [self updateDisplay]; } // ------------------------------------------------------- // (void) inverse:(id)sender // e^x // ------------------------------------------------------- - (void)powerE:(id)sender { [self saveState]; [em powerE]; [self updateDisplay]; } // ------------------------------------------------------- // (void) inverse:(id)sender // 10^x // ------------------------------------------------------- - (void)power10:(id)sender { [self saveState]; [em power10]; [self updateDisplay]; } // ------------------------------------------------------- // (void) inverse:(id)sender // ------------------------------------------------------- - (void)inverse:(id)sender { [self saveState]; [em inverse]; [self updateDisplay]; } // ===================================================================================== // TRIGOMETRIC FUNCTIONS // ===================================================================================== // ------------------------------------------------------- // (void) setDegree:(id)sender // ------------------------------------------------------- - (void)setDegree:(id)sender { [self saveState]; [em setAngleType:DEGREE]; [self updateDisplay]; } // ------------------------------------------------------- // (void) setRadian:(id)sender // ------------------------------------------------------- - (void)setRadian:(id)sender { [self saveState]; [em setAngleType:RADIAN]; [self updateDisplay]; } // ------------------------------------------------------- // (void) setGradient:(id)sender // ------------------------------------------------------- - (void)setGradient:(id)sender { [self saveState]; [em setAngleType:GRADIENT]; [self updateDisplay]; } // ------------------------------------------------------- // (void) sine:(id)sender // ------------------------------------------------------- - (void)sine:(id)sender { [self saveState]; [em sine]; [self updateDisplay]; } // ------------------------------------------------------- // (void) cosine:(id)sender // ------------------------------------------------------- - (void)cosine:(id)sender { [self saveState]; [em cosine]; [self updateDisplay]; } // ------------------------------------------------------- // (void) tangent:(id)sender // ------------------------------------------------------- - (void)tangent:(id)sender { [self saveState]; [em tangent]; [self updateDisplay]; } // ------------------------------------------------------- // (void) arcsine:(id)sender // ------------------------------------------------------- - (void)arcsine:(id)sender { [self saveState]; [em arcsine]; [self updateDisplay]; } // ------------------------------------------------------- // (void) arccosine:(id)sender // ------------------------------------------------------- - (void)arccosine:(id)sender { [self saveState]; [em arccosine]; [self updateDisplay]; } // ------------------------------------------------------- // (void) arctangent:(id)sender // ------------------------------------------------------- - (void)arctangent:(id)sender { [self saveState]; [em arctangent]; [self updateDisplay]; } // ===================================================================================== // PROBABILITY FUNCTIONS // ===================================================================================== // ------------------------------------------------------- // (void) permutation:(id)sender // nPr // ------------------------------------------------------- - (void)permutation:(id)sender { [self saveState]; [em operation:NPR_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) combination:(id)sender // ------------------------------------------------------- - (void)combination:(id)sender { [self saveState]; [em operation:NCR_OP]; [self updateDisplay]; } // ------------------------------------------------------- // (void) random_num:(id)sender // ------------------------------------------------------- - (void)random_num:(id)sender { [self saveState]; [em random_num]; [self updateDisplay]; } @end