home *** CD-ROM | disk | FTP | other *** search
- /*
- 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
-