Annotation of Examples/AppKit/SortingInAction/SortController.m, revision 1.1.1.1

1.1       root        1: 
                      2: /* The SortController class is the "brains" of the sorting operations.  As the 
                      3:  * shepherd of a flock of sorts, it keeps an array of Sort objects.  The 
                      4:  * SortController starts off the sort trials when the SortApp gets the "go!" 
                      5:  * signal.  The SortController generates the data and forks off the sort 
                      6:  * threads.  It keeps track of when the sorts finish, starts the next sort 
                      7:  * when the sorts are running in series, and lets the SortApp know when all 
                      8:  * the sorts have finished. Most of the controls of the Parameters panel send 
                      9:  * their target-action methods to the SortController and it sends the changes 
                     10:  * on to the sorts as necessary.  The SortController is also the text delegate 
                     11:  * for the various text fields and forms of the Parameters panel.  It does 
                     12:  * entry checking to make sure the user enters reasonable values.
                     13:  *
                     14:  * Author: Julie Zelenski, NeXT Developer Support
                     15:  * You may freely copy, distribute and reuse the code in this example.  
                     16:  * NeXT disclaims any warranty of any kind, expressed or implied, as to 
                     17:  * its fitness for any particular use.
                     18:  */
                     19: 
                     20: #import <appkit/appkit.h>
                     21: #import "SortController.h"
                     22: #import "BubbleSort.h"
                     23: #import "InsertionSort.h"
                     24: #import "MergeSort.h"
                     25: #import "QuickSort.h"
                     26: #import "SelectionSort.h"
                     27: #import "ShellSort.h"
                     28: #import "SortApp.h"
                     29: #import "SortView.h"
                     30: #import <libc.h>
                     31: #import <math.h>
                     32: #import <mach/cthreads.h>
                     33: 
                     34: 
                     35: extern BOOL Abort;             // global variable to signal abort 
                     36: 
                     37:  
                     38: @implementation SortController:Object
                     39: 
                     40: 
                     41: - init;
                     42: /* The initialization method is called once, when unarchiving the nib section.  
                     43:  * There is only one instantiation of the SortConroller object. This method 
                     44:  * creates a new sort object for each algorithm and initializes some instance
                     45:  * variables.
                     46:  */
                     47: {  
                     48:     [super init];
                     49:     srandom(time(0));                  // Seed random for data generating
                     50:                                        // Create on of each sort object
                     51:     sort[BUBBLE_SORT] = [[BubbleSort allocFromZone:[self zone]] init];
                     52:     sort[INSERTION_SORT] = [[InsertionSort allocFromZone:[self zone]] init];
                     53:     sort[MERGE_SORT] = [[MergeSort allocFromZone:[self zone]] init];
                     54:     sort[QUICK_SORT] = [[QuickSort allocFromZone:[self zone]] init];
                     55:     sort[SELECTION_SORT] = [[SelectionSort allocFromZone:[self zone]] init];
                     56:     sort[SHELL_SORT] = [[ShellSort allocFromZone:[self zone]] init];
                     57:     sortOn[QUICK_SORT] =  sortOn[INSERTION_SORT] = sortOn[SHELL_SORT] = YES;
                     58:     sortOn[BUBBLE_SORT] = sortOn[SELECTION_SORT] = sortOn[MERGE_SORT] = NO;
                     59:     numSorts = 3;
                     60:     parallel = YES;
                     61:     numElements = 50;
                     62:     percentSorted = 0;
                     63:     return self;
                     64: }
                     65: 
                     66: #define SIZE 1         // tags for different text fields
                     67: #define PERCENT 2
                     68: #define COMPARE 3
                     69: #define MOVE 4
                     70: #define FCALL 5        
                     71: 
                     72: 
                     73: /* TEXT DELEGATE METHODS */
                     74: 
                     75: 
                     76: - (BOOL)textWillEnd:textObject;
                     77: /* Checks to make sure that the entry in each of the text fields is reasonable. 
                     78:  * Different values are reasonable based on what the field is.  You can get the 
                     79:  * field or form being edited by asking the text object for its delegate.  If 
                     80:  * the value is unreasonable, reject it, and set the value back to the closest
                     81:  * reasonable value. Then it sends the action to the target so that change is 
                     82:  * recorded.
                     83:  */
                     84: {   
                     85:     BOOL entryOK = YES;
                     86:     id form;
                     87:     int value;
                     88:     
                     89:     form = [textObject delegate];
                     90:     value = [[form selectedCell] intValue];
                     91:     
                     92:     switch ([form selectedTag]) {
                     93:        case SIZE:      entryOK = (value > 0 );
                     94:                        if (value>5000) [[form selectedCell] setIntValue:5000];
                     95:                        break;
                     96:        case PERCENT:   entryOK = ((value >= 0) && (value <= 100));
                     97:                        break;
                     98:        case FCALL:       
                     99:        case MOVE:      
                    100:        case COMPARE:   entryOK = (value >= 0);
                    101:                        break;
                    102:     }
                    103:     if (entryOK) [form sendAction:[form action] to:[form target]];
                    104:     return (!entryOK);
                    105: }
                    106: 
                    107: 
                    108: 
                    109: /*  TARGET-ACTION METHODS (for controls in the Sort Parameters panel) */
                    110:  
                    111: - changeAnimate:sender
                    112: /* Changes whether the sorts highlight their comparisions. SortController 
                    113:  * simply passes this method onto each of the sorts.
                    114:  */
                    115: {   int c;
                    116:     BOOL value = (BOOL)[sender state];
                    117:     
                    118:     for (c = 0; c < NUM_SORT_TYPES; c++) 
                    119:         [sort[c] setAnimate:value];
                    120:     return self;
                    121: }
                    122: 
                    123: 
                    124: - changeParallel:sender
                    125: /* Changes whether the sorts run in parallel or series. SortController needs 
                    126:  * this to know whether to launch all sort threads at once, or to wait until 
                    127:  * one has finished to start the next sort.
                    128:  */
                    129: {
                    130:     parallel = (BOOL)[sender selectedTag];
                    131:     return self;
                    132: }
                    133: 
                    134: 
                    135: - changeSpeed:sender;
                    136: /* Changes at what speed the sorts are running.  SortController simply passes 
                    137:  * this method onto each of the sorts.
                    138:  */
                    139: {
                    140:     int c, speed;
                    141:     speed = [(Slider *)sender maxValue] - [sender intValue];
                    142:     for (c = 0; c < NUM_SORT_TYPES; c++) 
                    143:        [sort[c] setSpeed:speed];
                    144:     return self;
                    145: }
                    146: 
                    147: 
                    148: - changeSortOn:sender
                    149: /* Changes whether a selected sort is set to run or not.  Increments or 
                    150:  * decrements the number of sorts in this trial as appropriate.
                    151:  */
                    152: {   BOOL on; 
                    153: 
                    154:     on = (BOOL)[[sender selectedCell] state];
                    155:     sortOn[[sender selectedTag]] = on;
                    156:     if (on) 
                    157:        numSorts++;
                    158:     else 
                    159:        numSorts--;
                    160:     return self;
                    161: }
                    162: 
                    163: 
                    164:          
                    165: - changeDataSet:sender;
                    166: /* Changes the size or percent sorted of a data set, uses tag to determine 
                    167:  * which.
                    168:  */
                    169: {
                    170:     switch ([sender selectedTag]) {
                    171:         case SIZE:     numElements = [sender intValue];
                    172:                        break;
                    173:         case PERCENT:   percentSorted = [sender intValue];
                    174:                        break;
                    175:     }
                    176:     return self;
                    177: }
                    178: 
                    179: 
                    180: - changeTickValue:sender;
                    181: /* Changes the tick cost of a certain operation, uses tag to determine which.  
                    182:  * SortController simply passes this method onto each of the sorts.
                    183:  */
                    184: {
                    185:     int c, value;
                    186:     
                    187:     value = [sender intValue];
                    188:     for (c = 0; c < NUM_SORT_TYPES; c++) 
                    189:         [sort[c] setTicks:value for:[sender selectedTag]];
                    190:     return self;
                    191: }
                    192: 
                    193: 
                    194: 
                    195: 
                    196: /* PRIVATE METHODS */
                    197: 
                    198: 
                    199: - setSortWindow:anObject
                    200: /* The sortWindow is where all the animation takes place.
                    201:  */
                    202: {   
                    203:     sortWindow = anObject;  
                    204:     [[sortWindow contentView] setFlipped:YES];     
                    205:     return self;
                    206: }
                    207: 
                    208: 
                    209: - setUpWindow;
                    210: /* This is the method that adjusts the sorting window for a new trial.  It 
                    211:  * resizes the window to fit all the needed sort views and then adds those 
                    212:  * sortviews as subviews of the content view.  It removes any sortviews of
                    213:  * sorts that aren't scheduled to run in this trial.
                    214:  */
                    215: {
                    216:     NXPoint pt = {2.0,2.0};
                    217:     NXRect windowRect,headerRect;
                    218:     float newHeight;
                    219:     int c;
                    220:     
                    221:     [sortWindow disableFlushWindow];
                    222:     [sortWindow getFrame:&windowRect];
                    223:     [windowHeader getFrame:&headerRect];
                    224:     newHeight = headerRect.size.height + numSorts*(VIEW_HEIGHT+2) + 24;
                    225:     windowRect.origin.y += windowRect.size.height - newHeight;
                    226:     windowRect.size.height = newHeight;
                    227:     [sortWindow placeWindow:&windowRect];
                    228:     [windowHeader moveTo:headerRect.origin.x :-3];
                    229:     pt.y = headerRect.size.height;
                    230:     for (c = 0; (c < NUM_SORT_TYPES); c++) {
                    231:         if (sortOn[c]) {
                    232:            [[sort[c] view] moveTo:pt.x :pt.y];
                    233:            [[sortWindow contentView] addSubview:[sort[c] view]];
                    234:            pt.y += VIEW_HEIGHT+2.0;
                    235:        } else {
                    236:            [[sort[c] view] removeFromSuperview]; 
                    237:        }
                    238:      }   
                    239:      [sortWindow display];
                    240:      [[[sortWindow reenableFlushWindow] flushWindow] orderFront:self];
                    241:      return self;
                    242: }
                    243: 
                    244: 
                    245: - (int *)newDataSet
                    246: /* This is the method to generate a new data set.  Basically, it cycles 
                    247:  * through a loop numElements times, getting a new number for each position 
                    248:  * of the array.  For completely random data, each element is randomly 
                    249:  * generated.  For partially sorted data, only some of the elements are random, 
                    250:  * others are inserted in sorted position.  Each time through the loop, a 
                    251:  * random number is first generated to determine whether this array element 
                    252:  * will be random. If the random number is greater than the percent sorted, 
                    253:  * it will generate a random number for that array element, otherwise it will 
                    254:  * assign an element in sorted order to that array element. */
                    255: {    
                    256:     int max,c,*data;
                    257:     
                    258:     data = (int *)calloc(numElements,sizeof(int));
                    259:     max = floor((VIEW_HEIGHT-15.0)/(ceil((float)numElements/(VIEW_WIDTH-6))));    
                    260:     for (c = 0; c < numElements ;c++) {
                    261:         cthread_yield();       // give the interface a change
                    262:        if (((random() % 100) + 1) > percentSorted)
                    263:             data[c] = (random() % (int)(max-1))+ 1;
                    264:        else 
                    265:            data[c] = (int)(c*(max/(float)numElements)) +1;
                    266:     }
                    267:     return data;
                    268: }
                    269: 
                    270: 
                    271: - setUpData;
                    272: /* This method sends a message to itself to generate a new data set and 
                    273:  * then passes that data set along to the sorts who are scheduled to run 
                    274:  * so they can make a copy of it.  The sorts will set up their sortviews 
                    275:  * and draw the data set. (by messaging back to main thread)
                    276:  */
                    277: {    
                    278:     int c, *address;
                    279:        
                    280:     address = [self newDataSet];
                    281:     for (c = 0; c < NUM_SORT_TYPES; c++) {
                    282:         if (sortOn[c]) 
                    283:             [sort[c] setSize:numElements address:address];
                    284:     }
                    285:     cfree(address);
                    286:     return self;
                    287: }
                    288: 
                    289: 
                    290: static any_t sortInThread(aSort)
                    291:   id aSort;
                    292: {
                    293:     return [aSort sort];
                    294: }
                    295: 
                    296:  
                    297: - doSort;
                    298: /* This method is called to run a complete trial.  It is launched as a thread, 
                    299:  * so from here on out, I can no longer safely draw and must message to the 
                    300:  * main thread.  This method generates the data for the trial, sets up all 
                    301:  * the sort views, starts the tick counter, and then launches the sort threads.
                    302:  */
                    303: {   int c;
                    304: 
                    305:     [self setUpData];
                    306:     if (!Abort) 
                    307:        [NXApp startTickCounter]; 
                    308:     for (c = 0; c < NUM_SORT_TYPES; c++) {
                    309:         if (sortOn[c]) {
                    310:            cthread_detach(cthread_fork(sortInThread,sort[c]));
                    311:            if (!parallel) 
                    312:                break;
                    313:        }                 
                    314:     }  
                    315:     return self;
                    316: }
                    317: 
                    318: 
                    319: static any_t doSort(self)
                    320:   id self;
                    321: {
                    322:     return [self doSort];
                    323: }
                    324: 
                    325: 
                    326: 
                    327: /* PUBLIC METHODS */
                    328: 
                    329: - (BOOL)startSort;
                    330: /* The SortApp object calls this method after the Go button is clicked.  
                    331:  * If there are no sorts to run or there is no data set, this method returns 
                    332:  * NO to the SortApp. Otherwise, I resize and set up the sorting window and 
                    333:  * launch a thread to "doSort" which generates the data and launches the sort 
                    334:  * threads.  By launching a thread, this method will return almost immediately, 
                    335:  * so the user isn't locked out while I do the work.
                    336:  */
                    337: {
                    338:     if (!numSorts || !numElements) 
                    339:         return NO;
                    340:     else {
                    341:         sortsFinished =  0;
                    342:         [self setUpWindow];
                    343:         cthread_detach(cthread_fork(doSort,self)); 
                    344:        return YES;
                    345:     } 
                    346: }
                    347: 
                    348: 
                    349: - sortFinished:(int)sortNum;
                    350: /* When a sort finishes, it messages back to the main thread who does the final
                    351:  * display.  The SortApp then calls this method so the SortController can 
                    352:  * launch the next sort if necessary (i.e. if the sorts are running in series).  
                    353:  * The SortController also keeps track of how many sorts still need to finish.  
                    354:  * If all sorts have finished, the SortController lets the SortApp know, so it 
                    355:  * can clean up, stop the tick counter and re-enable all the controls in the 
                    356:  * Parameters panel.
                    357:  */
                    358: {
                    359:     sortsFinished++;
                    360:     if (sortsFinished == numSorts)     // if all sorts finished,
                    361:         [NXApp allFinished];           // let SortApp know this
                    362:     else if (!parallel) {              // if in series, launch next sort
                    363:         while (!sortOn[++sortNum]) ;
                    364:        [NXApp startTickCounter]; 
                    365:         cthread_detach(cthread_fork(sortInThread,sort[sortNum]));
                    366:     }
                    367:   return self;
                    368: }
                    369: 
                    370: 
                    371: - findSortWithNum:(int)sortNum;
                    372: /* Simply returns the sort of the specified number.  Called by the SortApp 
                    373:  * who has only the number of the sort, but needs the actual sort object.
                    374:  */
                    375: {
                    376:     return sort[sortNum];
                    377: }
                    378: 
                    379: 
                    380: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.