ftp.nice.ch/pub/next/developer/resources/libraries/threadkit/ThreadKitDemo.NI.tar.gz#/ThreadKit-1.0-DEMO/Examples/SortingInAction/SortApp.m

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.