home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.0 / NeXTSTEP3.0.iso / NextDeveloper / Examples / DatabaseKit / AddressBook / AddressView.m < prev    next >
Text File  |  1992-07-09  |  11KB  |  399 lines

  1. /* AddressView.m:
  2.  * You may freely copy, distribute, and reuse the code in this example.
  3.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  4.  * fitness for any particular use.
  5.  *
  6.  * Written by Mai Nguyen, NeXT Developer Support
  7.  *
  8.  */
  9.  
  10. #import <appkit/appkit.h>
  11. #import <objc/List.h>
  12. #import <dbkit/DBRecordList.h>
  13. #import <dbkit/DBValue.h>
  14. #import <libc.h>
  15.  
  16. #import "AddressView.h"
  17. #import "Controller.h"
  18.  
  19. #define EMPTY_STRING NXLocalizedString("Cannot accept empty string", NULL, "Notify user that empty string input is not valid.")
  20.  
  21. static char cellName[100];
  22.  
  23. @implementation AddressView
  24.  
  25. - initFrame:(const NXRect *)frameRect
  26. {
  27.       NXSize interCellSpacing = {0.0, 0.0}, docSize;
  28.  
  29.   [    super initFrame:frameRect];
  30.       cellMatrix = [[Matrix alloc] initFrame:frameRect
  31.         mode:NX_LISTMODE
  32.         cellClass:[TextFieldCell class]
  33.         numRows:0
  34.         numCols:1];
  35.  
  36.       /*
  37.        * In the following lines,
  38.        * remember that "cellMatrix" is the matrix that will be installed
  39.        * in the scrollview, "self" is the scrollview.
  40.        */
  41.  
  42.           /* we don't want any space between the matrix's cells  */
  43.       [cellMatrix setIntercell:&interCellSpacing];
  44.           /* resize the matrix to contain the cells */
  45.      [cellMatrix sizeToCells];
  46.       [cellMatrix setAutosizeCells:YES];
  47.     
  48.       /*
  49.        * when the user clicks in the matrix and then drags the mouse out of
  50.        * scrollView's contentView, we want the matrix to scroll
  51.        */
  52.       [cellMatrix setAutoscroll:YES];
  53.           /* let the matrix stretch horizontally */
  54.       [cellMatrix setAutosizing:NX_WIDTHSIZABLE];  
  55.           /* Install the matrix as the docview of the scrollview */
  56.       [[self setDocView:cellMatrix] free];
  57.           /* set up the visible attributes of the scrollview */
  58.       [self setVertScrollerRequired:YES];
  59.       [self setBorderType:NX_BEZEL];
  60.           /* tell the subviews to resize along with the scrollview */
  61.       [self setAutoresizeSubviews:YES];
  62.           /* This is the only way to get the clipview to resize too */
  63.       [[cellMatrix superview] setAutoresizeSubviews:YES];
  64.           /* Allow the scrollview to stretch both horizontally and vertically */
  65.       [self setAutosizing:NX_WIDTHSIZABLE|NX_HEIGHTSIZABLE];
  66.           /* Resize the matrix tUDll the inside of the scrollview */
  67.      [self getContentSize:&docSize];
  68.        [cellMatrix sizeTo:docSize.width :docSize.height];
  69.  
  70.     /* Set the matrix single click action */
  71.     [cellMatrix setTarget:self];
  72.       [cellMatrix setAction:@selector(showInfo:)];
  73.       
  74.     /* Allocate DBValue instances for accessing record contents */
  75.     aValue = [[DBValue alloc] init];
  76.     aValue2 = [[DBValue alloc] init];
  77.     return self;
  78. }
  79.  
  80. - free
  81. {
  82.       [cellMatrix free];
  83.       return [super free];
  84. }
  85.  
  86. - cellMatrix
  87. {
  88.       return cellMatrix;
  89. }
  90.  
  91. /*
  92.  * Since we recycle the cells (via renewRows:cols:), we also set the state
  93.  * of each cell to 0 and unhighlight it.  If we don't do that, the recycled
  94.  * cells will display their previous state.
  95.  */
  96. - loadCellsFrom:sender
  97.  
  98. {
  99.     int i, cellCount;
  100.      const char *firstName, *lastName;
  101.     char buf[100];
  102.     DBRecordList *    recordList;
  103.     List *    propertyList;
  104.           
  105.     recordList = (DBRecordList *)[controller getRecordList];
  106.     propertyList = (List *)[controller getPropertyList];
  107.     cellCount = (int) [controller getRecordCount];
  108.     
  109.      if (cellCount == 0 )
  110.           return self;
  111.   
  112.        
  113.         /* tell the matrix there are 0 cells in it (but don't deallocate them) */
  114.       [cellMatrix renewRows:0 cols:1];
  115.       [cellMatrix lockFocus];        /* for highlightCellAt::lit: */
  116.       for (i=0;i<cellCount;i++) {
  117.         TextFieldCell *cell;
  118.             /*
  119.          * add a row to the matrix.  (This doesn't necessarily allocate a new
  120.          * cell, thanks to renewRows:cols:).
  121.          */
  122.         [cellMatrix addRow];
  123.         cell = [cellMatrix cellAt:i:0];
  124.             /* make sure the cell is neither selected nor highlighted */
  125.             [cellMatrix highlightCellAt:i:0 lit:NO];
  126.         [cell setState:0];
  127.         
  128.         /* install the string value in that cell */
  129.         [recordList getValue:aValue 
  130.                     forProperty:[propertyList objectAt:1]at:i];                                             
  131.         lastName= (const char *)[aValue stringValue];
  132.  
  133.         [recordList getValue:aValue2 
  134.                     forProperty:[propertyList objectAt:2]at:i];                                                         
  135.         firstName = (const char *)[aValue2 stringValue];
  136.         sprintf(buf, "%s %s", lastName, firstName);
  137.         [cell setStringValue:buf];
  138.         
  139.       }
  140.       [cellMatrix unlockFocus];
  141.       [cellMatrix sizeToCells];
  142.       [cellMatrix display];
  143.       
  144.       return self;
  145. }
  146.  
  147. /* Get the newly added row */
  148. - (int) getNewRow
  149. {
  150.     int i;
  151.     int count, row;
  152.     const char* name;
  153.     
  154.     count = [cellMatrix cellCount];
  155.     row = count;     /* Initialize row to a meaningful numberUD        for (i = 0; i < count; i++) {
  156.         name = [[cellMatrix cellAt:i:0] stringValue];
  157.         if (!strcmp(cellName, name) ) {
  158.             row = i;
  159.             break;
  160.         }
  161.     }
  162.     return row;
  163. }
  164.  
  165.  
  166. /* Show the information contained in each selected record
  167.  */
  168.  
  169. - showInfo:sender
  170. {
  171.     int index;
  172.     DBRecordList * recordList;
  173.     List *    propertyList;
  174.  
  175.     recordList = [controller getRecordList];
  176.     propertyList = [controller getPropertyList];
  177.  
  178.     index = [cellMatrix selectedRow];
  179.  
  180.         /* Find the person's id    */
  181.     
  182.     [recordList getValue:aValue forProperty:[propertyList objectAt:0]at:index];                                                                                                                                      
  183.     [ssnField setStringValue:(const char *)[aValue stringValue]];
  184.  
  185.  
  186.         /* Find the person's last name and first name */
  187.     [recordList getValue:aValue forProperty:[propertyList objectAt:1]at:index];                                                                                                                                      
  188.     [lnameField setStringValue: (const char *)[aValue stringValue]];
  189.  
  190.     [recordList getValue:aValue forProperty:[propertyList objectAt:2]at:index];                                                                     
  191.     [fnameField setStringValue:(const char *)[aValue stringValue]];
  192.  
  193.                 /* Find the person's phone number */
  194.     [recordList getValue:aValue forProperty:[propertyList objectAt:3]at:index];                                                                                                                                  
  195.     [phoneField setStringValue:(const char *)[aValue stringValue]];
  196.     
  197.         /* Find the person's address */
  198.     [recordList getValue:aValue forProperty:[propertyList objectAt:4]at:index];                                                                                                                                  
  199.     [addressField setStringValue:(const char *)[aValue stringValue]];
  200.  
  201.         /* Find the person's city of residence */
  202.     [recordList getValue:aValue forProperty:[propertyList objectAt:5]at:index];
  203.     [cityField setStringValue:(const char *)[aValue stringValue]];
  204.  
  205.  
  206.         /* Find the person's state of residence */
  207.     [recordList getValue:aValue forProperty:[propertyList objectAt:6]at:index];                                                                                                                                  
  208.     [stateField setStringValue:(const char *)[aValue stringValue]];
  209.  
  210.         /* Find the person's zip code */
  211.     [recordList getValue:aValue forProperty:[propertyList objectAt:7]at:index];                                                                                                                                  
  212.     [zipField setStringValue:(const char *)[aValue stringValue]];
  213.     return self;
  214. }
  215.  
  216. /* Add a new record at the specified index. 
  217.  */
  218. - addRecordFrom:sender at:(unsigned)index
  219. {        
  220.     DBRecordList *    recordList;
  221.     List *    propertyList;
  222.     
  223.     recordList = (DBRecordList *)[controller getRecordList];
  224.     propertyList = (List *)[controller getPropUDList];
  225.     
  226.             /* In order to get records in and out, 
  227.              *    we must use a value object all the time
  228.              */
  229.                     
  230.         /* add empty record */
  231.     [recordList insertRecordAt:index];
  232.     if ([self setNewRecordFrom:sender at:index] == nil) {
  233.         return nil;
  234.     }
  235.                                              
  236.     if ([recordList saveModifications] != 1)
  237.         return nil;
  238.             
  239.     return self;    
  240. }
  241.  
  242. /* Update the record specified at index.
  243.  */
  244.  
  245. - updateRecordFrom:sender at:(unsigned) index
  246. {
  247.     DBRecordList *    recordList;
  248.     List * propertyList;    
  249.         
  250.     recordList = (DBRecordList *)[controller getRecordList];
  251.     propertyList = (List *) [controller getPropertyList];
  252.         
  253.     if ([self setNewRecordFrom:sender at:index] == nil) {
  254.         return nil;
  255.     }
  256.     
  257.     if ([recordList saveModifications] != 1)
  258.         return nil;
  259.         
  260.     return self;
  261. }
  262.  
  263. /* Get the user input from the text fields. Note that if a field is empty,
  264.  * the operation (either insert or update) would fail. Also, for simplicity,
  265.  * an arbitrary contract number is assigned to new records.
  266.  */
  267. - setNewRecordFrom:sender at:(unsigned)index
  268. {
  269.     DBRecordList *aRecList;
  270.     List *aPropList;
  271.     const char *inputString;
  272.     const char *lastName;
  273.  
  274.     aRecList = (DBRecordList *)[controller getRecordList];
  275.     aPropList = (List *)[controller getPropertyList];
  276.     
  277.     /* get the ssn or author id */
  278.  
  279.      inputString = (const char *)[ssnField stringValue];
  280.     
  281.         /* If the string is empty, abort the operation */
  282.     if  ( !strcmp(inputString,"")){
  283.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  284.         return nil;
  285.      }
  286.     else {    
  287.         [aValue setStringValue:inputString];
  288.         [aRecList setValue:aValue forProperty:[aPropList objectAt:0] at:index];
  289.     }
  290.         
  291.         
  292.         /* set last name */        
  293.     lastName = (const char *)[lnameField stringValue];
  294.     if  ( !strcmp(lastName,"")){
  295.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  296.         return nil;
  297.      } 
  298.     else {
  299.         [aValue setStringValue:lastName];
  300.         [aRecList setValue:aValue forProperty:[aPropList objectAt:1] at:index];             
  301.     }
  302.         
  303.         
  304.         /* set first name */
  305.     inputString = (const char *)[fnameField stringValue];
  306.     if  ( !strcmp(inputString,"")){
  307.         NXRunAlertPanel (NULL, EMPTY_STRING, NULL, NULL, NULL);
  308.         return nil;
  309.      }
  310.     else {
  311.         [aValue setStringValue:(const char *)inputString];
  312.         [aRecList setValue:aValue forProperty:[aPropList objectAt:2] at:index];
  313.         sprintf( cellName, "%s %s", lastName, inputString);
  314.     }
  315.         
  316.             /* set phone number */
  317.     inputString = (const char *)[phoUDeld stringValue];
  318.     if  ( !strcmp(inputString,"")){
  319.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  320.         return nil;
  321.      }
  322.     else {      
  323.         [aValue setStringValue: inputString];
  324.         [aRecList setValue:aValue forProperty:[aPropList objectAt:3] at:index];
  325.     }
  326.     
  327.             /* set address */
  328.     inputString = (const char *)[addressField stringValue];
  329.     if  ( !strcmp(inputString,"")){
  330.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  331.         return nil;
  332.      }
  333.     else {
  334.         [aValue setStringValue: inputString];
  335.         [aRecList setValue:aValue forProperty:[aPropList objectAt:4] at:index];
  336.     }
  337.  
  338.             /* set city name */
  339.     inputString = (const char *)[cityField stringValue];
  340.     if  ( !strcmp(inputString,"")){
  341.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  342.         return nil;
  343.      } 
  344.     else {
  345.         [aValue setStringValue: inputString];
  346.         [aRecList setValue:aValue forProperty:[aPropList objectAt:5] at:index];
  347.     }
  348.  
  349.             /* set state */
  350.     inputString = (const char *)[stateField stringValue];
  351.     if  ( !strcmp(inputString,"")){
  352.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  353.         return nil;
  354.      }
  355.     else {      
  356.         [aValue setStringValue: inputString];
  357.         [aRecList setValue:aValue forProperty:[aPropList objectAt:6] at:index];
  358.     }
  359.  
  360.             /* set zip code */
  361.     inputString = (const char *)[zipField stringValue];
  362.     if  ( !strcmp(inputString,"")){
  363.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  364.         return nil;
  365.      } 
  366.     else {
  367.         [aValue setStringValue: inputString];
  368.         [aRecList setValue:aValue forProperty:[aPropList objectAt:7] at:index]; 
  369.     }
  370.  
  371.  
  372.         /* assign an arbitrary contract number 1 to the new record */
  373.     [aRecList getValue:aValue forProperty:[aPropList objectAt:8] at:index];
  374.     
  375.     if ( ![aValue intValue]) {
  376.         [aValue setIntValue:1];
  377.         [aRecList setValue:aValue forProperty:[aPropList objectAt:8] at:index];
  378.     }
  379.  
  380.     return self;
  381. }
  382.  
  383.  
  384.  
  385. - deleteSelectedRecord:sender
  386. {
  387.     int row;
  388.     DBRecordList * recordList;
  389.  
  390.     row = [cellMatrix selectedRow];
  391.     recordList = (DBRecordList *)[controller getRecordList];
  392.     [recordList deleteRecordAt:row];
  393.     if ([recordList saveModifications] != 1)
  394.         return nil;
  395.     return self;
  396. }
  397.  
  398. @end
  399.