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.