Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
CalcController.m
/* |
File: CalcController.m |
Author: AW, ES, and MCF |
Copyright: © Copyright 2000 Apple Computer, Inc. All rights reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
9 July 97 -- first version of application |
7/5/00 KG Updated for Project Builder on DP4 |
12/04/00 MCF Updated for Project Builder on Mac OS X Public Beta |
*/ |
#import "CalcController.h" |
@implementation CalcController |
//This method clears out the calculator display and info about the last operation, etc. |
- (void)clear:(id)sender |
{ |
//We have to autorelease the old object and then retain the new one to not leak memory. |
[displayedNumber autorelease]; |
displayedNumber = [[NSDecimalNumber zero] retain]; |
[enteredNumber autorelease]; |
enteredNumber = [[NSDecimalNumber zero] retain]; |
[displayView setDoubleValue: 0]; |
[self endEditingNumber]; |
lastOperation = kNoOperator; |
usedDecimalPoint = NO; |
} |
- (void)equals:(id)sender |
{ |
if (enteringNumber) |
{ |
[self endEditingNumber]; |
[self performLastOperation]; |
lastOperation = kNoOperator; |
[displayView setStringValue: [displayedNumber stringValue]]; |
} |
} |
//this method is called when you click a number button on the calculator |
- (void)insertDigit:(id)sender |
{ |
NSString* oldValue; |
if (!enteringNumber) |
{ |
[self beginEditingNumber]; |
} |
oldValue = [displayView stringValue]; |
[displayView setStringValue: [oldValue stringByAppendingString: [sender title]]]; |
} |
- (void)beginEditingNumber |
{ |
enteringNumber = YES; |
usedDecimalPoint = NO; |
[displayView setStringValue: @""]; |
[enteredNumber autorelease]; |
enteredNumber = [displayedNumber copy]; |
} |
- (void)endEditingNumber |
{ |
enteringNumber = NO; |
usedDecimalPoint = NO; |
[displayedNumber autorelease]; |
displayedNumber = [NSDecimalNumber decimalNumberWithString: [displayView stringValue]]; |
[displayedNumber retain]; |
} |
- (void)decimalPoint:(id)sender |
{ |
NSString* oldValue; |
if (!usedDecimalPoint) |
{ |
usedDecimalPoint = YES; |
if (!enteringNumber) |
{ |
[self beginEditingNumber]; |
[displayView setStringValue: @"0."]; |
} |
else |
{ |
oldValue = [displayView stringValue]; |
[displayView setStringValue: [oldValue stringByAppendingString: @"."]]; |
} |
} |
} |
//This method is called when the application first launches and instantiates this |
//object from the nib file |
-(void) awakeFromNib |
{ |
[self clear: self]; |
//This next line is a work-around for a bug in Mac OS X Public Beta |
[[displayView window] makeKeyAndOrderFront:nil]; |
} |
- (void)operation:(id)sender |
{ |
if (enteringNumber) |
{ |
[self endEditingNumber]; |
[self performLastOperation]; |
[displayView setStringValue: [displayedNumber stringValue]]; |
} |
// no matter what, set the new operation in case the user changes his/her mind |
lastOperation = [sender tag]; |
} |
- (void)performLastOperation |
{ |
if (lastOperation == kNoOperator) |
{ |
return; |
} |
// it is possible to extensively rewrite the following code. In all cases, |
// displayedNumber is autoreleased, assigned a new value and that new value is |
// retained. Thus it would reduce the number of lines of code to put the |
// autorelease statement before the nest of if statements, and put the retain |
// statement after the nest of if statements. However, I've duplicated the |
// statements just to brutally drive home the point that you need to autorelease |
// before you assign over your instance variables, and you need to retain them |
// after you've assigned to them. Even in the case that none of the if statements |
// are executed, autoreleaseing and immediately retaining the same object is |
// perfectly acceptable. |
// This way of detecting NANs is a HACK! Unfortunately, NaN is not ordered, so |
// if you ask any number if it's equal to NaN, it'll say yes. So, instead we'll |
// ask if it's equal to an impossible combination of numbers -- zero and one. |
// The only 'number' equal to both is NaN |
if ((([displayedNumber compare: [NSDecimalNumber zero]] == NSOrderedSame) && |
([displayedNumber compare: [NSDecimalNumber one]] == NSOrderedSame)) || |
(([enteredNumber compare: [NSDecimalNumber zero]] == NSOrderedSame) && |
([enteredNumber compare: [NSDecimalNumber one]] == NSOrderedSame))) |
{ |
[displayedNumber autorelease]; |
displayedNumber = [[NSDecimalNumber notANumber] retain]; |
return; |
} |
else if (lastOperation == kAddOperator) |
{ |
[displayedNumber autorelease]; |
displayedNumber = [enteredNumber decimalNumberByAdding: displayedNumber]; |
[displayedNumber retain]; |
} |
else if (lastOperation == kSubtractOperator) |
{ |
[displayedNumber autorelease]; |
displayedNumber = [enteredNumber decimalNumberBySubtracting: displayedNumber]; |
[displayedNumber retain]; |
} |
else if (lastOperation == kMultiplyOperator) |
{ |
[displayedNumber autorelease]; |
displayedNumber = [enteredNumber decimalNumberByMultiplyingBy: displayedNumber]; |
[displayedNumber retain]; |
} |
else if (lastOperation == kDivideOperator) |
{ |
if ([displayedNumber compare: [NSDecimalNumber zero]] != NSOrderedSame) |
{ |
[displayedNumber autorelease]; |
displayedNumber = [enteredNumber decimalNumberByDividingBy: displayedNumber]; |
[displayedNumber retain]; |
} |
else |
{ |
[displayedNumber autorelease]; |
displayedNumber = [[NSDecimalNumber notANumber] retain]; |
[displayedNumber retain]; |
} |
} |
} |
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication |
{ |
return YES; |
} |
- (void)cut:(id)sender |
{ |
[self copy: self]; |
[self clear: self]; |
} |
- (void)copy:(id)sender |
{ |
//grab the general pasteboard |
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; |
//tell the copy/paste system what type of data we'll be putting up there |
[pasteboard declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner: NULL]; |
//go ahead and place the display string on the pasteboard for other apps to paste |
[pasteboard setString: [displayView stringValue] forType: NSStringPboardType]; |
} |
- (void)paste:(id)sender |
{ |
NSPasteboard* pasteboard; |
NSString* pasteValue; |
if (!enteringNumber) |
{ |
[self beginEditingNumber]; |
} |
//grab the general pasteboard |
pasteboard = [NSPasteboard generalPasteboard]; |
//get the content from the pasteboard for our data type |
pasteValue = [pasteboard stringForType: NSStringPboardType]; |
//set the display of the calculator |
[displayView setStringValue: [[displayView stringValue] stringByAppendingString: pasteValue]]; |
} |
// when self is released, it is necessary to release all of the variables we've retained |
-(void)dealloc |
{ |
[displayedNumber release]; |
[enteredNumber release]; |
} |
@end |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-30