This is InputController.m in view mode; [Download] [Up]
/* File: InputController.m Contains: Source code for the Controller of the "Input" window, see also PopupInTable.m Written by: Eric Simenel Created: May 1997 Copyright: (c)1997 by Apple Computer, Inc., all rights reserved. Change History (most recent first): You may incorporate this sample code into your applications without restriction, though the sample code has been provided "AS IS" and the responsibility for its operation is 100% yours. However, what you are not permitted to do is to redistribute the source as "DSC Sample Code" after having made changes. If you're going to re-distribute the source, we require that you make it clear in the source that the code was descended from Apple Sample Code, but that you've made changes. */ #import "InputController.h" #import "ComicsObj.h" #import "PopupInTable.h" @implementation InputController // private helper method: update the UI when the data array has changed - (void)_update { // release the popup button [puit releasePub]; // update the table view [inputView noteNumberOfRowsChanged]; [inputView reloadData]; } // accessors - (NSMutableArray *)array { return array;} - (id)inputView { return inputView;} - (short *)curIshArray { return curIshArray;} - (short)theBuyMonth { return theBuyMonth;} - (short)theEditMonth { return theEditMonth;} - (NSFont *)fontProp { return fontProp;} - (NSFont *)fontNonProp { return fontNonProp;} - (void)setTheBuyMonth:(short)b { [selBuyMonth setIntValue:b]; [self selectBuyMonth:selBuyMonth]; } - (void)selectBuyMonth:(id)sender { [curBuyMonth setStringValue:[CComics nsStrDate:(theBuyMonth = [sender intValue])]]; } - (void)setTheEditMonth:(short)e { [selEditMonth setIntValue:e]; [self selectEditMonth:selEditMonth]; } - (void)selectEditMonth:(id)sender { short i; [curEditMonth setStringValue:[CComics nsStrDate:(theEditMonth = [sender intValue])]]; for(i=1; i <= 6; i++) { NSCell *cell = [[inputView tableColumnWithIdentifier:[NSString stringWithFormat:@"M%d",i]] headerCell]; if (((theEditMonth-1-6+i) % 12) == 0) [cell setStringValue:[NSString stringWithCString:gnums[(theEditMonth-1-6+i) / 12]]]; else [cell setStringValue:[NSString stringWithCString:gmonths[(theEditMonth-1-6+i) % 12]]]; } [self _update]; } - (void)doClick:(id)sender { short clickedRow, clickedColumn; clickedRow = [inputView clickedRow]; clickedColumn = [inputView clickedColumn]; // release the popup button [puit releasePub]; // reselect the current edited row in case releasePub (line above) has deselected it [inputView selectRow:clickedRow byExtendingSelection:NO]; // if the user has clicked in a column where a popup button should appear, then set it up if ((clickedColumn > 2) && (clickedColumn != 13) && (clickedColumn != 14)) [puit setUpPopup]; // if the user has clicked in the "Issue" column then we may have to slide the Edit Month to show it if (clickedColumn == 14) { CTitle *thisTitle = [array objectAtIndex:clickedRow]; short theIsh = curIshArray[clickedRow]; short theEMonth = [[[thisTitle issues] objectAtIndex:[thisTitle findIssue:theIsh]] editMonth]; // if this edit month (line above) is not in the visible area, slide the Edit Month to show it if ((theEMonth < theEditMonth-5) || (theEMonth > theEditMonth)) [self setTheEditMonth:theEMonth+3]; } } - (void)selChanged { short i; // get the right array of titles [comicsBase sortArray:array withBrand:brand withSeries:series withKind:kind withState:state withSort:sort]; nbRows = [array count]; // reset the local array which fills the "Issue" column with the latest issue for each title if (curIshArray) free(curIshArray); curIshArray = (short *)malloc(sizeof(short) * nbRows); for(i=0; i<nbRows; i++) curIshArray[i] = [[[[array objectAtIndex:i] issues] lastObject] issueNumber]; [nbSelTitles setIntValue:nbRows]; [self _update]; } - (void)contentChanged { // update the displayed static text boxes with appropriate values [nbIssues setIntValue:[comicsBase nbIssues]]; [nbTitles setIntValue:[comicsBase nbTitles]]; // mark the window as modified, so that the close box reflects this state and we'll know later if we have to // ask the user for saving changes [[inputView window] setDocumentEdited:YES]; // send the notification so that other Controllers will know about a change. [[NSNotificationCenter defaultCenter] postNotificationName:ComicsDidChangeNotification object:self]; } - (void)brandSelect:(id)sender { short newBrand = [sender indexOfSelectedItem]; if (newBrand != brand) { brand = newBrand; [self selChanged]; } } - (void)kindSelect:(id)sender { short newKind = [sender indexOfSelectedItem]; if (newKind != kind) { kind = newKind; [self selChanged]; } } - (void)seriesSelect:(id)sender { short newSeries = [sender indexOfSelectedItem]; if (newSeries != series) { series = newSeries; [self selChanged]; } } - (void)stateSelect:(id)sender { short newState = [sender indexOfSelectedItem]; if (newState != state) { state = newState; [self selChanged]; } } - (void)sortSelect:(id)sender { short newSort = [sender indexOfSelectedItem]; if (newSort != sort) { sort = newSort; [self selChanged]; } } - (void)addNewTitle:(id)sender { CTitle *thisTitle; CIssue *thisIssue; short flag = 0; flag |= (brand == 2)?mskDC:mskMarvel; flag |= (series == 2)?mskMini:mskLong; flag |= (state == 1)?mskDead:mskLive; flag |= (kind == 2)?mskDual:mskMain; thisTitle = [[CTitle alloc] initWithAbb:@"ZZZ" withTitle:@"Zzzzzzzzzz" withFlag:flag]; switch([comicsBase addTitle:thisTitle]) { case -2: NSRunAlertPanel(@"Comics", @"The title Zzzzzzzzzz already exists. Please change its name before you can create a new title.", @"OK", nil, nil); break; case -1: NSRunAlertPanel(@"Comics", @"The abbreviation ZZZ already exists. Please change its name before you can create a new title.", @"OK", nil, nil); break; case 0: thisIssue = [[CIssue alloc] initWithIsh:1 withEdit:theEditMonth withBuy:theBuyMonth withFlag:defaultFI]; [thisTitle addIssue:thisIssue]; [self selChanged]; [self contentChanged]; [inputView scrollRowToVisible:[array count]-1]; [inputView selectRow:[array count]-1 byExtendingSelection:NO]; break; } } - (void)deleteThisTitle:(id)sender { CTitle *thisTitle; if ([inputView selectedRow] >= [array count]) return; thisTitle = [array objectAtIndex:[inputView selectedRow]]; [comicsBase deleteTitle:thisTitle]; [self selChanged]; [self contentChanged]; } #define whitey 0.8 - (id)init { if (self = [super init]) { nbRows = 0; brand = 0; series = 0; kind = 0; state = 0; sort = 0; // I have a lttle less than 1500 titles currently, hence the following capacity... array = [[NSMutableArray alloc] initWithCapacity:1500]; curIshArray = (short *)nil; arrCol[0] = [[NSColor colorWithCalibratedRed:whitey green:1.0 blue:1.0 alpha:1.0] retain]; arrCol[1] = [[NSColor colorWithCalibratedRed:1.0 green:whitey blue:whitey alpha:1.0] retain]; arrCol[2] = [[NSColor colorWithCalibratedRed:whitey green:1.0 blue:whitey alpha:1.0] retain]; arrCol[3] = [[NSColor colorWithCalibratedRed:whitey green:whitey blue:1.0 alpha:1.0] retain]; arrCol[4] = [[NSColor colorWithCalibratedRed:1.0 green:1.0 blue:whitey alpha:1.0] retain]; arrCol[5] = [[NSColor colorWithCalibratedRed:1.0 green:whitey blue:1.0 alpha:1.0] retain]; fontProp = [[NSFont fontWithName:@"Helvetica" size:10] retain]; fontNonProp = [[NSFont fontWithName:@"Ohlfs" size:10] retain]; } return self; } - (void)dealloc { int i; for(i=0; i<6; i++) [arrCol[i] release]; [fontProp release]; [fontNonProp release]; [array release]; [super dealloc]; } - (void)userHasScrolled:(id)sender { // if the user has scrolled then release the pop up button [puit releasePub]; // and call back the original target and action of the vertical scroller so that we actually scroll... (see below) [myVerticalScroller sendAction:saveVerticalScrollerAction to:saveVerticalScrollerTarget]; } - (void)awakeFromNib { NSCalendarDate *date; NSView *aView; // finding the NSScrollView superview... for(aView=inputView; ![aView isKindOfClass:[NSScrollView class]]; aView = [aView superview]); myVerticalScroller = [(NSScrollView *)aView verticalScroller]; // saving the current target and action of the vertical scroller to be able to call them later in userHasScrolled saveVerticalScrollerTarget = [myVerticalScroller target]; saveVerticalScrollerAction = [myVerticalScroller action]; // set the new target and action. Much more elegant than patching, much more efficient than subclassing. [myVerticalScroller setTarget:self]; [myVerticalScroller setAction:@selector(userHasScrolled:)]; theEditMonth = [comicsBase lastEditMonth] + 1; date = [NSCalendarDate calendarDate]; theBuyMonth = [date monthOfYear] + 12 * ([date yearOfCommonEra] -1900); [selEditMonth setMinValue:[comicsBase startEditMonth]]; [selEditMonth setMaxValue:theEditMonth]; [self setTheEditMonth:theEditMonth]; [selBuyMonth setMinValue:[comicsBase startBuyMonth]]; [selBuyMonth setMaxValue:theBuyMonth]; [self setTheBuyMonth:theBuyMonth]; [nbIssues setIntValue:[comicsBase nbIssues]]; [nbTitles setIntValue:[comicsBase nbTitles]]; [inputView setRowHeight:14]; [inputView setIntercellSpacing:NSMakeSize(1, 0)]; [[[inputView tableColumns] objectAtIndex:2] setMinWidth:4]; [[[inputView tableColumns] objectAtIndex:2] setWidth:4]; [[[inputView tableColumns] objectAtIndex:13] setMinWidth:4]; [[[inputView tableColumns] objectAtIndex:13] setWidth:4]; [self selChanged]; } // Since numberOfRowsInTableView is called a ZILLION times by the NSTableView object methods, // do the number of rows calculation in selChanged, and save off the value in the nbRows field // so that I can just return the value. - (int)numberOfRowsInTableView:(NSTableView *)tableView { return nbRows; } // This method is called just before objectValueForTableColumn and allows us to modify the graphical aspect of the cell: // font, size, color, background color, etc. - (void)tableView:(NSTableView *)tv willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)row { NSString *identifier = [tableColumn identifier]; [cell setFont:([identifier cString][0] == 'M')?fontNonProp:fontProp]; if ([identifier isEqualToString:@"CurIsh"]) [cell setFont:fontNonProp]; if ([identifier isEqualToString:@"Empty"]) if (row == [tv selectedRow]) [cell setBackgroundColor:[NSColor redColor]]; else [cell setBackgroundColor:[NSColor blackColor]]; else if ((row == [tv editedRow]) && ([tv columnWithIdentifier:identifier] == [tv editedColumn])) [cell setBackgroundColor:[NSColor whiteColor]]; else [cell setBackgroundColor:arrCol[row % 6]]; [cell setDrawsBackground:YES]; } - (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row { CIssue *thisIssue; CTitle *thisTitle = [array objectAtIndex:row]; NSString *identifier = [tableColumn identifier], *result; thisIssue = [[thisTitle issues] objectAtIndex:[thisTitle findIssue:curIshArray[row]]]; if ([identifier isEqualToString:@"Abb"]) result = [thisTitle abb]; else if ([identifier isEqualToString:@"Title"]) result = [thisTitle title]; else if ([identifier isEqualToString:@"Brand"]) result = [thisTitle brand]; else if ([identifier isEqualToString:@"Series"]) result = [thisTitle series]; else if ([identifier isEqualToString:@"State"]) result = [thisTitle tstate]; else if ([identifier isEqualToString:@"Kind"]) result = [thisTitle kind]; else if ([identifier isEqualToString:@"CurIsh"]) result = [NSString stringWithCString:gnums[curIshArray[row]]]; else if ([identifier isEqualToString:@"Grade"]) result = [thisIssue grade]; else if ([identifier isEqualToString:@"Type"]) result = [thisIssue ishtype]; else if ([identifier isEqualToString:@"Content"]) result = [thisIssue content]; else // column identifiers "M1" to "M6" { short k, j = -1, i = theEditMonth - 6 + [identifier cString][1] - '0'; for(k = [thisTitle nbIssues]-1; (k >= 0) && (j == -1); k--) if (([thisIssue = [[thisTitle issues] objectAtIndex:k] editMonth] == i) && !([thisIssue issueFlags] & mskMiss)) j = k; if (j == -1) result = @""; else result = [NSString stringWithCString:gnums[[thisIssue issueNumber]]]; } return result; } - (void)tableView:(NSTableView *)tv setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row { NSString *identifier = [tableColumn identifier]; CTitle *thisTitle = [array objectAtIndex:row]; if ((([identifier isEqualToString:@"Abb"]) && (![[thisTitle abb] isEqualToString:object])) || (([identifier isEqualToString:@"Title"]) && (![[thisTitle title] isEqualToString:object]))) { CTitle *newTit = [[CTitle alloc] initWithAbb:[thisTitle abb] withTitle:[thisTitle title] withFlag:[thisTitle titleFlags]]; if ([identifier isEqualToString:@"Abb"]) [newTit setAbb:object]; else [newTit setTitle:object]; [comicsBase modTitle:thisTitle withNewTitle:newTit]; [array replaceObjectAtIndex:row withObject:newTit]; [self contentChanged]; } else if ([identifier cString][0] == 'M') { CIssue *newIssue; short thisIssueNumber = [object intValue], j, ed = (theEditMonth - 6 + [identifier cString][1] - '0'); if (thisIssueNumber >= 0) if ((j = ([thisTitle findIssue:thisIssueNumber])) == -1) { newIssue = [[CIssue alloc] initWithIsh:thisIssueNumber withEdit:ed withBuy:theBuyMonth withFlag:defaultFI]; [thisTitle addIssue:newIssue]; [self contentChanged]; } // I don't allow the modification of an issue from typing its issue number, too dangerous... else NSRunAlertPanel(@"Comics", @"Sorry, you can't modify an existing issue by typing.", @"OK", nil, nil); [tableColumn setEditable:NO]; } } - (BOOL)windowShouldClose:(id)sender { if (![[inputView window] isDocumentEdited]) return YES; switch(NSRunAlertPanel(@"Comics", @"The comics database has been edited. Save?", @"Save", @"Don't save", @"Cancel")) { case NSAlertDefaultReturn:[comicsBase save:nil]; break; case NSAlertAlternateReturn:break; case NSAlertOtherReturn:return NO; break; } return YES; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.