This is AddressView.m in view mode; [Download] [Up]
/* AddressView.m: * You may freely copy, distribute, and reuse the code in this example. * NeXT disclaims any warranty of any kind, expressed or implied, as to its * fitness for any particular use. * * Written by Mai Nguyen, NeXT Developer Support * */ #import <appkit/appkit.h> #import <objc/List.h> #import <dbkit/DBRecordList.h> #import <dbkit/DBValue.h> #import <libc.h> #import "AddressView.h" #import "Controller.h" #define EMPTY_STRING NXLocalizedString("Cannot accept empty string", NULL, "Notify user that empty string input is not valid.") static char cellName[100]; @implementation AddressView - initFrame:(const NXRect *)frameRect { NXSize interCellSpacing = {0.0, 0.0}, docSize; [ super initFrame:frameRect]; cellMatrix = [[Matrix alloc] initFrame:frameRect mode:NX_LISTMODE cellClass:[TextFieldCell class] numRows:0 numCols:1]; /* * In the following lines, * remember that "cellMatrix" is the matrix that will be installed * in the scrollview, "self" is the scrollview. */ /* we don't want any space between the matrix's cells */ [cellMatrix setIntercell:&interCellSpacing]; /* resize the matrix to contain the cells */ [cellMatrix sizeToCells]; [cellMatrix setAutosizeCells:YES]; /* * when the user clicks in the matrix and then drags the mouse out of * scrollView's contentView, we want the matrix to scroll */ [cellMatrix setAutoscroll:YES]; /* let the matrix stretch horizontally */ [cellMatrix setAutosizing:NX_WIDTHSIZABLE]; /* Install the matrix as the docview of the scrollview */ [[self setDocView:cellMatrix] free]; /* set up the visible attributes of the scrollview */ [self setVertScrollerRequired:YES]; [self setBorderType:NX_BEZEL]; /* tell the subviews to resize along with the scrollview */ [self setAutoresizeSubviews:YES]; /* This is the only way to get the clipview to resize too */ [[cellMatrix superview] setAutoresizeSubviews:YES]; /* Allow the scrollview to stretch both horizontally and vertically */ [self setAutosizing:NX_WIDTHSIZABLE|NX_HEIGHTSIZABLE]; /* Resize the matrix to fill the inside of the scrollview */ [self getContentSize:&docSize]; [cellMatrix sizeTo:docSize.width :docSize.height]; /* Set the matrix single click action */ [cellMatrix setTarget:self]; [cellMatrix setAction:@selector(showInfo:)]; /* Allocate DBValue instances for accessing record contents */ aValue = [[DBValue alloc] init]; aValue2 = [[DBValue alloc] init]; return self; } - free { [cellMatrix free]; if (aValue) [aValue free]; if (aValue2) [aValue2 free]; return [super free]; } - cellMatrix { return cellMatrix; } /* * Since we recycle the cells (via renewRows:cols:), we also set the state * of each cell to 0 and unhighlight it. If we don't do that, the recycled * cells will display their previous state. */ - loadCellsFrom:sender { int i, cellCount; const char *firstName, *lastName; char buf[100]; DBRecordList * recordList; List * propertyList; recordList = (DBRecordList *)[controller getRecordList]; propertyList = (List *)[controller getPropertyList]; cellCount = (int) [controller getRecordCount]; if (cellCount == 0 ) return self; /* tell the matrix there are 0 cells in it (but don't deallocate them) */ [cellMatrix renewRows:0 cols:1]; [cellMatrix lockFocus]; /* for highlightCellAt::lit: */ for (i=0;i<cellCount;i++) { TextFieldCell *cell; /* * add a row to the matrix. (This doesn't necessarily allocate a new * cell, thanks to renewRows:cols:). */ [cellMatrix addRow]; cell = [cellMatrix cellAt:i:0]; /* make sure the cell is neither selected nor highlighted */ [cellMatrix highlightCellAt:i:0 lit:NO]; [cell setState:0]; /* install the string value in that cell */ [recordList getValue:aValue forProperty:[propertyList objectAt:1]at:i]; lastName= (const char *)[aValue stringValue]; [recordList getValue:aValue2 forProperty:[propertyList objectAt:2]at:i]; firstName = (const char *)[aValue2 stringValue]; sprintf(buf, "%s %s", lastName, firstName); [cell setStringValue:buf]; } [cellMatrix unlockFocus]; [cellMatrix sizeToCells]; [cellMatrix display]; return self; } /* Get the newly added row */ - (int) getNewRow { int i; int count, row; const char* name; count = [cellMatrix cellCount]; row = count; /* Initialize row to a meaningful number */ for (i = 0; i < count; i++) { name = [[cellMatrix cellAt:i:0] stringValue]; if (!strcmp(cellName, name) ) { row = i; break; } } return row; } /* Show the information contained in each selected record */ - showInfo:sender { int index; DBRecordList * recordList; List * propertyList; recordList = [controller getRecordList]; propertyList = [controller getPropertyList]; index = [cellMatrix selectedRow]; /* Find the person's id */ [recordList getValue:aValue forProperty:[propertyList objectAt:0]at:index]; [ssnField setStringValue:(const char *)[aValue stringValue]]; /* Find the person's last name and first name */ [recordList getValue:aValue forProperty:[propertyList objectAt:1]at:index]; [lnameField setStringValue: (const char *)[aValue stringValue]]; [recordList getValue:aValue forProperty:[propertyList objectAt:2]at:index]; [fnameField setStringValue:(const char *)[aValue stringValue]]; /* Find the person's phone number */ [recordList getValue:aValue forProperty:[propertyList objectAt:3]at:index]; [phoneField setStringValue:(const char *)[aValue stringValue]]; /* Find the person's address */ [recordList getValue:aValue forProperty:[propertyList objectAt:4]at:index]; [addressField setStringValue:(const char *)[aValue stringValue]]; /* Find the person's city of residence */ [recordList getValue:aValue forProperty:[propertyList objectAt:5]at:index]; [cityField setStringValue:(const char *)[aValue stringValue]]; /* Find the person's state of residence */ [recordList getValue:aValue forProperty:[propertyList objectAt:6]at:index]; [stateField setStringValue:(const char *)[aValue stringValue]]; /* Find the person's zip code */ [recordList getValue:aValue forProperty:[propertyList objectAt:7]at:index]; [zipField setStringValue:(const char *)[aValue stringValue]]; return self; } /* Add a new record at the specified index. */ - addRecordFrom:sender at:(unsigned)index { DBRecordList * recordList; List * propertyList; recordList = (DBRecordList *)[controller getRecordList]; propertyList = (List *)[controller getPropertyList]; /* In order to get records in and out, * we must use a value object all the time */ /* add empty record */ [recordList insertRecordAt:index]; if ([self setNewRecordFrom:sender at:index] == nil) { return nil; } if ([recordList saveModifications] == 0) return self; return nil; } /* Update the record specified at index. */ - updateRecordFrom:sender at:(unsigned) index { DBRecordList * recordList; List * propertyList; recordList = (DBRecordList *)[controller getRecordList]; propertyList = (List *) [controller getPropertyList]; if ([self setNewRecordFrom:sender at:index] == nil) { return nil; } if ([recordList saveModifications] == 0) return self; return nil; } /* Get the user input from the text fields. Note that if a field is empty, * the operation (either insert or update) would fail. Also, for simplicity, * an arbitrary contract number is assigned to new records. */ - setNewRecordFrom:sender at:(unsigned)index { DBRecordList *aRecList; List *aPropList; const char *inputString; const char *lastName; aRecList = (DBRecordList *)[controller getRecordList]; aPropList = (List *)[controller getPropertyList]; /* get the ssn or author id */ inputString = (const char *)[ssnField stringValue]; /* If the string is empty, abort the operation */ if ( !strcmp(inputString,"")){ NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL); return nil; } else { [aValue setStringValue:inputString]; [aRecList setValue:aValue forProperty:[aPropList objectAt:0] at:index]; } /* set last name */ lastName = (const char *)[lnameField stringValue]; if ( !strcmp(lastName,"")){ NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL); return nil; } else { [aValue setStringValue:lastName]; [aRecList setValue:aValue forProperty:[aPropList objectAt:1] at:index]; } /* set first name */ inputString = (const char *)[fnameField stringValue]; if ( !strcmp(inputString,"")){ NXRunAlertPanel (NULL, EMPTY_STRING, NULL, NULL, NULL); return nil; } else { [aValue setStringValue:(const char *)inputString]; [aRecList setValue:aValue forProperty:[aPropList objectAt:2] at:index]; sprintf( cellName, "%s %s", lastName, inputString); } /* set phone number */ inputString = (const char *)[phoneField stringValue]; if ( !strcmp(inputString,"")){ NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL); return nil; } else { [aValue setStringValue: inputString]; [aRecList setValue:aValue forProperty:[aPropList objectAt:3] at:index]; } /* set address */ inputString = (const char *)[addressField stringValue]; if ( !strcmp(inputString,"")){ NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL); return nil; } else { [aValue setStringValue: inputString]; [aRecList setValue:aValue forProperty:[aPropList objectAt:4] at:index]; } /* set city name */ inputString = (const char *)[cityField stringValue]; if ( !strcmp(inputString,"")){ NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL); return nil; } else { [aValue setStringValue: inputString]; [aRecList setValue:aValue forProperty:[aPropList objectAt:5] at:index]; } /* set state */ inputString = (const char *)[stateField stringValue]; if ( !strcmp(inputString,"")){ NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL); return nil; } else { [aValue setStringValue: inputString]; [aRecList setValue:aValue forProperty:[aPropList objectAt:6] at:index]; } /* set zip code */ inputString = (const char *)[zipField stringValue]; if ( !strcmp(inputString,"")){ NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL); return nil; } else { [aValue setStringValue: inputString]; [aRecList setValue:aValue forProperty:[aPropList objectAt:7] at:index]; } /* assign an arbitrary contract number 1 to the new record */ [aRecList getValue:aValue forProperty:[aPropList objectAt:8] at:index]; if ( ![aValue intValue]) { [aValue setIntValue:1]; [aRecList setValue:aValue forProperty:[aPropList objectAt:8] at:index]; } return self; } - deleteSelectedRecord:sender { int row; DBRecordList * recordList; row = [cellMatrix selectedRow]; recordList = (DBRecordList *)[controller getRecordList]; [recordList deleteRecordAt:row]; if ([recordList saveModifications] == 0) return self; else return nil; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.