Annotation of Examples/AppKit/SortingInAction/SortController.m, revision 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.