This is SortApp.m in view mode; [Download] [Up]
/* * This class is in charge of application-wide activity such as handling the * main menu commands, enabling and disabling controls and managing the tick * counter display. It is also responsible for receiving drawing requests * from the sort threads. When any thread needs to draw, it conjures up a * simple Mach message which it sends to the drawing port that the SortApp * monitors. The SortApp will have the appropriate view do the necessary * drawing. * * Author: Julie Zelenski, NeXT Developer Support * You may freely copy, distribute and reuse the code in this example. * NeXT disclaims any warranty of any kind, expressed or implied, as to * its fitness for any particular use. */ #import <appkit/appkit.h> #import "SortApp.h" #import "SortController.h" #import "GenericSort.h" #import "SortView.h" #import <string.h> /* Global variables shared across several class/threads. */ BOOL Abort; // global variable to signal abort int TickCount; // global variable of current tick count mutex_t TickLock; // mutual exclusion to protect TickCount condition_t TickUpdated; // signaled when TickCount is increased @implementation SortApp + initialize; /* +initialize is sent to the factory object for SortApp before any * other messages are sent. This is a good place to allocate and initialize * the global variables. */ { if (self == [SortApp class]) { Abort = NO; TickCount = 0; TickLock = mutex_alloc(); TickUpdated = condition_alloc(); } return self; } + new; { self = [super new]; teNum = (DPSTimedEntry)0; return self; } /* TARGET-ACTION METHODS */ - info:sender /* * The info panel is a separate nib module and only loaded on demand. */ { if (!infoPanel) { if (![self loadNibSection:"InfoPanel.nib" owner:self withNames:NO]) { NXLogError ("Could not load InfoPanel.nib"); } } [infoPanel makeKeyAndOrderFront:self]; return self; } - help:sender /* * The help panel is a separate nib module and only loaded on demand. */ { if (!helpPanel) { if (![self loadNibSection:"HelpPanel.nib" owner:self withNames:NO]) { NXLogError ("Could not load HelpPanel.nib"); } } [helpPanel makeKeyAndOrderFront:self]; return self; } - go:sender /* * This button gets the whole thing going. It disables the controls that * will be inactive while the sort is running, resets the tick counter, and * asks the SortController to start the trial. The SortController will launch * a thread to generate the data and run the sorts, so this method will return * almost immediately. That way the user interface of the program remains * responsive. The user can stop the sort, change the speed, go look at the * Info panel, whatever! When a sort is running, this button becomes the Stop * button, used to cancel a sort in progress. */ { if (!strcmp([sender icon],"Stop")) // if sorting, this is "Stop" button return [self stop:self]; if ([[goButton window] makeFirstResponder:[goButton window]]) { if ([sortController startSort]) { // if trial got started ok [self setControlsEnabled:NO]; [messageField setStringValue: [stringTable valueForStringKey:"Data"]]; [tickField setIntValue:0]; } } return self; } - stop:sender /* * This method cancels a sort in progress the whole thing going. It stops * the tick counter and sets the global variable Abort to YES. The sorting * threads continually check this variable and when the recognize it they * send one last message to the drawPort which will display the canceled * sort. When they have all check in, the method allFinished will do any * necessary clean up. */ { Abort = YES; // threads will pick up on this & report back when killed [messageField setStringValue:[stringTable valueForStringKey:"Canceled"]]; condition_broadcast(TickUpdated); [self stopTickCounter]; return self; } - setControlsEnabled:(BOOL)value; /* This method is called to disable all the inactive controls in the parameter * window while a sort is in progress (the data set size, percent sorted, etc). * This method is also called to enable those controls when the sorts have * finished. */ { [[performRadios window] disableFlushWindow]; [performRadios setEnabled:value]; [dataSetMatrix setEnabled:value]; [algorithmMatrix setEnabled:value]; [tickValueMatrix setEnabled:value]; [tickMatrix setEnabled:value]; if (value) [goButton setIcon:"Go!"]; else [goButton setIcon:"Stop"]; [[[performRadios window] reenableFlushWindow] flushWindow]; return self; } - allFinished; /* This method is sent by the SortController when it has verified that * all sorts have finished in the current trial. It will stop the tick * counter, re-enable the controls, and reset Abort to NO. */ { [self stopTickCounter]; [self setControlsEnabled:YES]; if (!Abort) [messageField setStringValue:[stringTable valueForStringKey:"Done"]]; Abort = NO; return self; } - setTickField:anObject /* * The tickField is a text field on the animation window that displays the * tick count. When a sort is running, a timed entry is called every second * to update the tick field. The timed entry runs at a priority one higher * than NXMODALRESPTHRESHOLD. Because of this, the tick field is updated even * during a modal response loop (such as changing the speed slider). */ { tickField = anObject; [tickField allocateGState]; // for more efficient lock/unlock focus return self; } static void updateTick (teNum,now,self) DPSTimedEntry teNum; double now; SortApp *self; { mutex_lock(TickLock); [self->tickField setIntValue:TickCount]; // display current tick count mutex_unlock(TickLock); } - startTickCounter; /* This method is called to reset the tick count to zero and to kick off the * timed entry that will update the tick field display every second. */ { TickCount = 0; if (teNum) DPSRemoveTimedEntry(teNum); teNum = DPSAddTimedEntry(1.0, &updateTick, self, NX_MODALRESPTHRESHOLD +1); return self; } - stopTickCounter; /* This method is called to remove the timed entry that has been updating the * tick field every second. The tick field will display the current tick * count. */ { if (teNum) DPSRemoveTimedEntry(teNum); teNum = (DPSTimedEntry)0; [tickField setIntValue:TickCount]; return self; } - stringTable; /* This method simply returns the string table for other objects which need to * access strings. */ { return stringTable; } - notifyDone: (int) sortNum { return [sortController sortFinished:sortNum]; } - notifySorting { if (!Abort) { [messageField setStringValue: [stringTable valueForStringKey:"Sorting"]]; } return self ; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.