home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / OPENSTEP / Utilities / Comics-1.0-MIS / InputController.m < prev    next >
Encoding:
Text File  |  1997-09-25  |  14.8 KB  |  368 lines

  1. /*
  2.  File:       InputController.m
  3.  
  4.  Contains:   Source code for the Controller of the "Input" window, see also PopupInTable.m
  5.  
  6.  Written by: Eric Simenel
  7.  
  8.  Created:    May 1997
  9.  
  10.  Copyright:  (c)1997 by Apple Computer, Inc., all rights reserved.
  11.  
  12.  Change History (most recent first):
  13.  
  14.  You may incorporate this sample code into your applications without
  15.  restriction, though the sample code has been provided "AS IS" and the
  16.  responsibility for its operation is 100% yours.  However, what you are
  17.  not permitted to do is to redistribute the source as "DSC Sample Code"
  18.  after having made changes. If you're going to re-distribute the source,
  19.  we require that you make it clear in the source that the code was
  20.  descended from Apple Sample Code, but that you've made changes.
  21. */
  22.  
  23. #import "InputController.h"
  24. #import "ComicsObj.h"
  25. #import "PopupInTable.h"
  26.  
  27. @implementation InputController
  28.  
  29. // private helper method: update the UI when the data array has changed
  30. - (void)_update
  31. {
  32.     // release the popup button
  33.     [puit releasePub];
  34.     // update the table view
  35.     [inputView noteNumberOfRowsChanged];
  36.     [inputView reloadData];
  37. }
  38.  
  39. // accessors
  40. - (NSMutableArray *)array { return array;}
  41. - (id)inputView { return inputView;}
  42. - (short *)curIshArray { return curIshArray;}
  43. - (short)theBuyMonth { return theBuyMonth;}
  44. - (short)theEditMonth { return theEditMonth;}
  45. - (NSFont *)fontProp { return fontProp;}
  46. - (NSFont *)fontNonProp { return fontNonProp;}
  47. - (void)setTheBuyMonth:(short)b
  48. {
  49.     [selBuyMonth setIntValue:b];
  50.     [self selectBuyMonth:selBuyMonth];
  51. }
  52. - (void)selectBuyMonth:(id)sender
  53. {
  54.     [curBuyMonth setStringValue:[CComics nsStrDate:(theBuyMonth = [sender intValue])]];
  55. }
  56. - (void)setTheEditMonth:(short)e
  57. {
  58.     [selEditMonth setIntValue:e];
  59.     [self selectEditMonth:selEditMonth];
  60. }
  61. - (void)selectEditMonth:(id)sender
  62. {
  63.     short i;
  64.     [curEditMonth setStringValue:[CComics nsStrDate:(theEditMonth = [sender intValue])]];
  65.     for(i=1; i <= 6; i++)
  66.       {
  67.         NSCell *cell = [[inputView tableColumnWithIdentifier:[NSString stringWithFormat:@"M%d",i]] headerCell];
  68.         if (((theEditMonth-1-6+i) % 12) == 0)
  69.             [cell setStringValue:[NSString stringWithCString:gnums[(theEditMonth-1-6+i) / 12]]];
  70.         else
  71.             [cell setStringValue:[NSString stringWithCString:gmonths[(theEditMonth-1-6+i) % 12]]];
  72.       }
  73.     [self _update];
  74. }
  75.  
  76. - (void)doClick:(id)sender
  77. {
  78.     short clickedRow, clickedColumn;
  79.     clickedRow = [inputView clickedRow];
  80.     clickedColumn = [inputView clickedColumn];
  81.     // release the popup button
  82.     [puit releasePub];
  83.     // reselect the current edited row in case releasePub (line above) has deselected it
  84.     [inputView selectRow:clickedRow byExtendingSelection:NO];
  85.     // if the user has clicked in a column where a popup button should appear, then set it up
  86.     if ((clickedColumn > 2) && (clickedColumn != 13) && (clickedColumn != 14)) [puit setUpPopup];
  87.     // if the user has clicked in the "Issue" column then we may have to slide the Edit Month to show it
  88.     if (clickedColumn == 14)
  89.       {
  90.         CTitle *thisTitle = [array objectAtIndex:clickedRow];
  91.         short theIsh = curIshArray[clickedRow];
  92.         short theEMonth = [[[thisTitle issues] objectAtIndex:[thisTitle findIssue:theIsh]] editMonth];
  93.         // if this edit month (line above) is not in the visible area, slide the Edit Month to show it
  94.         if ((theEMonth < theEditMonth-5) || (theEMonth > theEditMonth)) [self setTheEditMonth:theEMonth+3];
  95.       }
  96. }
  97.  
  98. - (void)selChanged
  99. {
  100.     short i;
  101.     // get the right array of titles
  102.     [comicsBase sortArray:array withBrand:brand withSeries:series withKind:kind withState:state withSort:sort];
  103.     nbRows = [array count];
  104.     // reset the local array which fills the "Issue" column with the latest issue for each title
  105.     if (curIshArray) free(curIshArray);
  106.     curIshArray = (short *)malloc(sizeof(short) * nbRows);
  107.     for(i=0; i<nbRows; i++) curIshArray[i] = [[[[array objectAtIndex:i] issues] lastObject] issueNumber];
  108.  
  109.     [nbSelTitles setIntValue:nbRows];
  110.     [self _update];
  111. }
  112. - (void)contentChanged
  113. {
  114.     // update the displayed static text boxes with appropriate values
  115.     [nbIssues setIntValue:[comicsBase nbIssues]];
  116.     [nbTitles setIntValue:[comicsBase nbTitles]];
  117.     // mark the window as modified, so that the close box reflects this state and we'll know later if we have to
  118.     // ask the user for saving changes
  119.     [[inputView window] setDocumentEdited:YES];
  120.     // send the notification so that other Controllers will know about a change.
  121.     [[NSNotificationCenter defaultCenter] postNotificationName:ComicsDidChangeNotification object:self];
  122. }
  123.  
  124. - (void)brandSelect:(id)sender
  125. {
  126.     short newBrand = [sender indexOfSelectedItem];
  127.     if (newBrand != brand) { brand = newBrand; [self selChanged]; }
  128. }
  129. - (void)kindSelect:(id)sender
  130. {
  131.     short newKind = [sender indexOfSelectedItem];
  132.     if (newKind != kind) { kind = newKind; [self selChanged]; }
  133. }
  134. - (void)seriesSelect:(id)sender
  135. {
  136.     short newSeries = [sender indexOfSelectedItem];
  137.     if (newSeries != series) { series = newSeries; [self selChanged]; }
  138. }
  139. - (void)stateSelect:(id)sender
  140. {
  141.     short newState = [sender indexOfSelectedItem];
  142.     if (newState != state) { state = newState; [self selChanged]; }
  143. }
  144. - (void)sortSelect:(id)sender
  145. {
  146.     short newSort = [sender indexOfSelectedItem];
  147.     if (newSort != sort) { sort = newSort; [self selChanged]; }
  148. }
  149.  
  150. - (void)addNewTitle:(id)sender
  151. {
  152.     CTitle *thisTitle;
  153.     CIssue *thisIssue;
  154.     short flag = 0;
  155.     flag |= (brand == 2)?mskDC:mskMarvel;
  156.     flag |= (series == 2)?mskMini:mskLong;
  157.     flag |= (state == 1)?mskDead:mskLive;
  158.     flag |= (kind == 2)?mskDual:mskMain;
  159.     thisTitle = [[CTitle alloc] initWithAbb:@"ZZZ" withTitle:@"Zzzzzzzzzz" withFlag:flag];
  160.     switch([comicsBase addTitle:thisTitle])
  161.       {
  162.         case -2:
  163.             NSRunAlertPanel(@"Comics", @"The title Zzzzzzzzzz already exists. Please change its name before you can create a new title.", @"OK", nil, nil);
  164.             break;
  165.         case -1:
  166.             NSRunAlertPanel(@"Comics", @"The abbreviation ZZZ already exists. Please change its name before you can create a new title.", @"OK", nil, nil);
  167.             break;
  168.         case 0:
  169.             thisIssue = [[CIssue alloc] initWithIsh:1 withEdit:theEditMonth withBuy:theBuyMonth withFlag:defaultFI];
  170.             [thisTitle addIssue:thisIssue];
  171.             [self selChanged];
  172.             [self contentChanged];
  173.             [inputView scrollRowToVisible:[array count]-1];
  174.             [inputView selectRow:[array count]-1 byExtendingSelection:NO];
  175.             break;
  176.       }
  177. }
  178. - (void)deleteThisTitle:(id)sender
  179. {
  180.     CTitle *thisTitle;
  181.     if ([inputView selectedRow] >= [array count]) return;
  182.     thisTitle = [array objectAtIndex:[inputView selectedRow]];
  183.     [comicsBase deleteTitle:thisTitle];
  184.     [self selChanged];
  185.     [self contentChanged];
  186. }
  187.  
  188. #define whitey 0.8
  189.  
  190. - (id)init
  191. {
  192.    if (self = [super init])
  193.      {
  194.        nbRows = 0;
  195.        brand = 0;
  196.        series = 0;
  197.        kind = 0;
  198.        state = 0;
  199.        sort = 0;
  200.        // I have a lttle less than 1500 titles currently, hence the following capacity...
  201.        array = [[NSMutableArray alloc] initWithCapacity:1500];
  202.        curIshArray = (short *)nil;
  203.        arrCol[0] = [[NSColor colorWithCalibratedRed:whitey green:1.0 blue:1.0 alpha:1.0] retain];
  204.        arrCol[1] = [[NSColor colorWithCalibratedRed:1.0 green:whitey blue:whitey alpha:1.0] retain];
  205.        arrCol[2] = [[NSColor colorWithCalibratedRed:whitey green:1.0 blue:whitey alpha:1.0] retain];
  206.        arrCol[3] = [[NSColor colorWithCalibratedRed:whitey green:whitey blue:1.0 alpha:1.0] retain];
  207.        arrCol[4] = [[NSColor colorWithCalibratedRed:1.0 green:1.0 blue:whitey alpha:1.0] retain];
  208.        arrCol[5] = [[NSColor colorWithCalibratedRed:1.0 green:whitey blue:1.0 alpha:1.0] retain];
  209.        fontProp = [[NSFont fontWithName:@"Helvetica" size:10] retain];
  210.        fontNonProp = [[NSFont fontWithName:@"Ohlfs" size:10] retain];
  211.      }
  212.    return self;
  213. }
  214. - (void)dealloc
  215. {
  216.     int i;
  217.     for(i=0; i<6; i++) [arrCol[i] release];
  218.     [fontProp release];
  219.     [fontNonProp release];
  220.     [array release];
  221.     [super dealloc];
  222. }
  223. - (void)userHasScrolled:(id)sender
  224. {
  225.     // if the user has scrolled then release the pop up button
  226.     [puit releasePub];
  227.     // and call back the original target and action of the vertical scroller so that we actually scroll... (see below)
  228.     [myVerticalScroller sendAction:saveVerticalScrollerAction to:saveVerticalScrollerTarget];
  229. }
  230. - (void)awakeFromNib
  231. {
  232.    NSCalendarDate *date;
  233.    NSView *aView;
  234.  
  235.    // finding the NSScrollView superview...
  236.    for(aView=inputView; ![aView isKindOfClass:[NSScrollView class]]; aView = [aView superview]);
  237.    myVerticalScroller = [(NSScrollView *)aView verticalScroller];
  238.    // saving the current target and action of the vertical scroller to be able to call them later in userHasScrolled
  239.    saveVerticalScrollerTarget = [myVerticalScroller target];
  240.    saveVerticalScrollerAction = [myVerticalScroller action];
  241.    // set the new target and action. Much more elegant than patching, much more efficient than subclassing.
  242.    [myVerticalScroller setTarget:self];
  243.    [myVerticalScroller setAction:@selector(userHasScrolled:)];
  244.  
  245.    theEditMonth = [comicsBase lastEditMonth] + 1;
  246.    date = [NSCalendarDate calendarDate];
  247.    theBuyMonth = [date monthOfYear] + 12 * ([date yearOfCommonEra] -1900);
  248.  
  249.    [selEditMonth setMinValue:[comicsBase startEditMonth]];
  250.    [selEditMonth setMaxValue:theEditMonth];
  251.    [self setTheEditMonth:theEditMonth];
  252.    [selBuyMonth setMinValue:[comicsBase startBuyMonth]];
  253.    [selBuyMonth setMaxValue:theBuyMonth];
  254.    [self setTheBuyMonth:theBuyMonth];
  255.  
  256.    [nbIssues setIntValue:[comicsBase nbIssues]];
  257.    [nbTitles setIntValue:[comicsBase nbTitles]];
  258.  
  259.    [inputView setRowHeight:14];
  260.    [inputView setIntercellSpacing:NSMakeSize(1, 0)];
  261.    [[[inputView tableColumns] objectAtIndex:2] setMinWidth:4];
  262.    [[[inputView tableColumns] objectAtIndex:2] setWidth:4];
  263.    [[[inputView tableColumns] objectAtIndex:13] setMinWidth:4];
  264.    [[[inputView tableColumns] objectAtIndex:13] setWidth:4];
  265.  
  266.    [self selChanged];
  267. }
  268.  
  269. // Since numberOfRowsInTableView is called a ZILLION times by the NSTableView object methods,
  270. // do the number of rows calculation in selChanged, and save off the value in the nbRows field
  271. // so that I can just return the value.
  272. - (int)numberOfRowsInTableView:(NSTableView *)tableView
  273. {
  274.    return nbRows;
  275. }
  276.  
  277. // This method is called just before objectValueForTableColumn and allows us to modify the graphical aspect of the cell:
  278. // font, size, color, background color, etc.
  279. - (void)tableView:(NSTableView *)tv willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)row
  280. {
  281.     NSString *identifier = [tableColumn identifier];
  282.     [cell setFont:([identifier cString][0] == 'M')?fontNonProp:fontProp];
  283.     if ([identifier isEqualToString:@"CurIsh"]) [cell setFont:fontNonProp];
  284.     if ([identifier isEqualToString:@"Empty"])
  285.         if (row == [tv selectedRow])
  286.             [cell setBackgroundColor:[NSColor redColor]];
  287.         else
  288.             [cell setBackgroundColor:[NSColor blackColor]];
  289.     else if ((row == [tv editedRow]) && ([tv columnWithIdentifier:identifier] == [tv editedColumn]))
  290.         [cell setBackgroundColor:[NSColor whiteColor]];
  291.     else
  292.         [cell setBackgroundColor:arrCol[row % 6]];
  293.     [cell setDrawsBackground:YES];
  294. }
  295.  
  296. - (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
  297. {
  298.     CIssue *thisIssue;
  299.     CTitle *thisTitle = [array objectAtIndex:row];
  300.     NSString *identifier = [tableColumn identifier], *result;
  301.     thisIssue = [[thisTitle issues] objectAtIndex:[thisTitle findIssue:curIshArray[row]]];
  302.     if ([identifier isEqualToString:@"Abb"]) result = [thisTitle abb];
  303.     else if ([identifier isEqualToString:@"Title"]) result = [thisTitle title];
  304.     else if ([identifier isEqualToString:@"Brand"]) result = [thisTitle brand];
  305.     else if ([identifier isEqualToString:@"Series"]) result = [thisTitle series];
  306.     else if ([identifier isEqualToString:@"State"]) result = [thisTitle tstate];
  307.     else if ([identifier isEqualToString:@"Kind"]) result = [thisTitle kind];
  308.     else if ([identifier isEqualToString:@"CurIsh"]) result = [NSString stringWithCString:gnums[curIshArray[row]]];
  309.     else if ([identifier isEqualToString:@"Grade"]) result = [thisIssue grade];
  310.     else if ([identifier isEqualToString:@"Type"]) result = [thisIssue ishtype];
  311.     else if ([identifier isEqualToString:@"Content"]) result = [thisIssue content];
  312.     else // column identifiers "M1" to "M6"
  313.       {
  314.         short k, j = -1, i = theEditMonth - 6 + [identifier cString][1] - '0';
  315.         for(k = [thisTitle nbIssues]-1; (k >= 0) && (j == -1); k--)
  316.             if (([thisIssue = [[thisTitle issues] objectAtIndex:k] editMonth] == i) && !([thisIssue issueFlags] & mskMiss)) j = k;
  317.         if (j == -1) result = @"";
  318.         else result = [NSString stringWithCString:gnums[[thisIssue issueNumber]]];
  319.       }
  320.     return result;
  321. }
  322.  
  323. - (void)tableView:(NSTableView *)tv setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
  324. {
  325.     NSString *identifier = [tableColumn identifier];
  326.     CTitle *thisTitle = [array objectAtIndex:row];
  327.     if ((([identifier isEqualToString:@"Abb"]) && (![[thisTitle abb] isEqualToString:object])) ||
  328.         (([identifier isEqualToString:@"Title"]) && (![[thisTitle title] isEqualToString:object])))
  329.       {
  330.         CTitle *newTit = [[CTitle alloc] initWithAbb:[thisTitle abb] withTitle:[thisTitle title] withFlag:[thisTitle titleFlags]];
  331.         if ([identifier isEqualToString:@"Abb"]) [newTit setAbb:object]; else [newTit setTitle:object];
  332.         [comicsBase modTitle:thisTitle withNewTitle:newTit];
  333.  
  334.         [array replaceObjectAtIndex:row withObject:newTit];
  335.  
  336.         [self contentChanged];
  337.       }
  338.     else if ([identifier cString][0] == 'M')
  339.       {
  340.         CIssue *newIssue;
  341.         short thisIssueNumber = [object intValue], j, ed = (theEditMonth - 6 + [identifier cString][1] - '0');
  342.         if (thisIssueNumber >= 0)
  343.             if ((j = ([thisTitle findIssue:thisIssueNumber])) == -1)
  344.               {
  345.                 newIssue = [[CIssue alloc] initWithIsh:thisIssueNumber withEdit:ed withBuy:theBuyMonth withFlag:defaultFI];
  346.                 [thisTitle addIssue:newIssue];
  347.                 [self contentChanged];
  348.               }
  349.             // I don't allow the modification of an issue from typing its issue number, too dangerous...
  350.             else NSRunAlertPanel(@"Comics", @"Sorry, you can't modify an existing issue by typing.", @"OK", nil, nil);
  351.         [tableColumn setEditable:NO];
  352.       }
  353. }
  354.  
  355. - (BOOL)windowShouldClose:(id)sender
  356. {
  357.     if (![[inputView window] isDocumentEdited]) return YES;
  358.     switch(NSRunAlertPanel(@"Comics", @"The comics database has been edited. Save?", @"Save", @"Don't save", @"Cancel"))
  359.       {
  360.         case NSAlertDefaultReturn:[comicsBase save:nil]; break;
  361.         case NSAlertAlternateReturn:break;
  362.         case NSAlertOtherReturn:return NO; break;
  363.       }
  364.     return YES;
  365. }
  366.  
  367. @end
  368.