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

  1. /* Controller.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!1pkit/appkit.h>     
  11. #import    <dbkit/dbkit.h>
  12. #import <libc.h>
  13. #import "Controller.h"
  14.  
  15. /* Define localized strings */
  16. #define INSTALL_MODEL NXLocalizedString("Please install SybaseDemo.dbmodel into your ~/Library/Databases directory and restart.", NULL, "Notify user that SybaseDemo.dbmodel must be installed in his local Databases directory.")
  17. #define EMPTY_STRING NXLocalizedString("Cannot accept empty string", NULL, "Notify user that empty string input is not valid.")
  18. #define INSERT_FAILED NXLocalizedString("Insert operation failed", NULL, "Notify user that insert operation has failed.")
  19.  
  20. static char newAuthorID[100];
  21.  
  22. @implementation Controller
  23.  
  24. /* Extract the actual database and recordlist from the DBModule UI Object
  25.  */ 
  26. -appDidInit:sender
  27. {
  28.         /* Notify the user if the database can't be found */
  29.     if (![DBDatabase findDatabaseNamed:"SybaseDemo" connect:YES]) {
  30.         NXRunAlertPanel(NULL,INSTALL_MODEL, "OK", NULL, NULL);
  31.         return self;
  32.     }    
  33.       dbDatabase = [dbModule database];
  34.     dbFetchGroup = [dbModule rootFetchGroup];
  35.     dbRecordList = [dbFetchGroup recordList];
  36.     recordOrder = DB_AscendingOrder;
  37.     dbQualifier = nil;
  38.     
  39.             /* Initialize the retrieval order to be ascending order
  40.              */
  41.     sortProp = [[dbModule entity] propertyNamed:"lastName"];
  42.             
  43.     [dbRecordList addRetrieveOrder:recordOrder for:sortProp];
  44.         
  45.             /* Assign the controller object to be the delegate of dbFetchGroup.
  46.              * See also the method fetchGroup:didInsertRecordAt:
  47.              */
  48.     [dbFetchGroup setDelegate:self];
  49.     
  50.             /* Assign the record list of the root fetchgroup to be the delegate
  51.              * of DBBinder. This is a convenient way to make sure that the proper
  52.              * qualifier will be used at fetch time.
  53.              * See also the method binderWillSelect:
  54.              */
  55.     [[dbFetchGroup recordList] setBinderDelegate:self];
  56.     
  57.             /* Create a DBValue instance to be used later for accessing data
  58.              * inside a record list.
  59.              */
  60.     aValue = [[DBValue alloc] init];
  61.     
  62.     [theWindow makeKeyAndOrderFront:nil];
  63.     return self;
  64. }
  65.  
  66. /* Change the retrieval order for the record list. To be set before pressing
  67.  * SELECT.
  68.  */
  69. -changeRetrieveOrder:sender
  70. {
  71.     recordOrder = [sender selectedTag];
  72.     return self;
  73. }
  74.  
  75. /* Build the DBQualifier before a SELECT operation. Note that you should give
  76.  * the external names as defined in dbModel for properties.
  77.  */
  78. - buildSelectQualifier:sender
  79. {
  80.     const char * state;
  81.     id!1teProperty;
  82.     
  83.     state = [qualifierField stringValue];
  84.     if (!strcmp(state,"")) {
  85.         dbQualifier = nil;
  86.         return nil;
  87.     }
  88.     else {
  89.     stateProperty = [[dbModule entity] propertyNamed:"state"];
  90.     dbQualifier = [[DBQualifier allocFromZone:[self zone] ] 
  91.         initForEntity:[dbModule entity]
  92.         fromDescription:"%@ LIKE %s", stateProperty, state];
  93.     }
  94.     return self;
  95. }
  96.  
  97. /* This method is called when the SELECT button is pressed.
  98.  * NOTE: If the qualifier form has a NULL string, the source is set to nil,
  99.  * which means that ALL records will be fetched. 
  100.  */
  101. - select:sender
  102. {
  103.     id    source;
  104.  
  105.     [self buildSelectQualifier:nil];    
  106.     if (!dbQualifier)
  107.         source = nil;
  108.     else
  109.         source = [dbModule entity];
  110.         
  111.     [dbFetchGroup fetchContentsOf:source usingQualifier:dbQualifier];
  112.     
  113.         /* Update the display */
  114.     [self display];
  115.     return self;
  116. }
  117.  
  118. /* This method is called when the INSERT button is pressed. Check for blank
  119.  * record fields before the actual INSERT.
  120.  */
  121. - insert:sender
  122. {
  123.     if ([self checkInputRecord:sender]==nil)
  124.         NXRunAlertPanel(NULL,INSERT_FAILED, "OK", NULL, NULL);
  125.     else
  126.         [dbModule insertNewRecord:sender];
  127.     [self display];
  128.     return self;
  129. }
  130.     
  131. /* Try to highlight the newly added row based on the token "newAuthorID".
  132.  * This method is called everytime the SELECT button is pressed.
  133.  * If there is no match, the first row is highlighted by default.
  134.  */
  135. - display
  136. {
  137.     int rowCount, i, row;
  138.     id socSecProperty;
  139.     const char *keyValue;
  140.     
  141.     row = 0;
  142.         /* Search for a match only if the ID has meaningful data */
  143.     if ( strlen(newAuthorID) > 0 ) {
  144.         rowCount = [dbTableView rowCount];
  145.         socSecProperty = [[dbModule entity] propertyNamed:"authorID"];
  146.         for (i= 0; i < rowCount; i++) {
  147.             [dbRecordList getValue:aValue forProperty:socSecProperty at:i];
  148.             keyValue = (const char *)[aValue stringValue];
  149.             if (!strcmp(keyValue, newAuthorID)) {
  150.                 row = i;
  151.                 break; }
  152.         }
  153.     }
  154.     [dbFetchGroup setCurrentRecord:row];
  155.     [dbTableView display];
  156.     return self;
  157. }
  158.  
  159.  
  160. /* evaluateSQL
  161.  * This method uses a DBBinder object which will evaluate SQL queries entered
  162.  * by the user.
  163.  * Note that the results returned from the evaluation are PROPERTIES only.
  164.  * For example, if you enter: "select * from authors", all properties of the
  165.  * authors table will be returned. However, if you enter: "select au_lname from
  166.  * authors where state = 'CA'", only the last name property will be returne!1* You can reuse this code and substitute the query string with a Sybase stored
  167.  * procedure.
  168.  * Another possibility to evaluate a Sybase stored procedure would be to become
  169.  * the binder's delegate, and use the delegate methods binderWillSelect: or 
  170.  * binderDidSelect: to call the binder method evaluateString in order to launch
  171.  * the stored procedure.
  172.  */
  173. - evaluateSQL:sender
  174. {
  175.      int i,c, pc;
  176.     const char * queryString;
  177.     char buf[256];
  178.       id bind = [[DBBinder alloc] init];
  179.      id list = [[List alloc] init];
  180.      id propertyList = [[List alloc] init];
  181.       id prop = nil;
  182.       
  183.         /* set up the binder */
  184.        [bind setDatabase:dbDatabase];
  185.       [bind setContainer:list];
  186.       
  187.       if (queryString = [queryField stringValue]) {
  188.         [self appendToView:textView text:"SQL>>"];
  189.         [bind reset];
  190.         [bind evaluateString:queryString];
  191.         [bind fetch];
  192.         [bind getProperties:propertyList];
  193.         sprintf(buf, "Number of records found:  %d\n", (c=[list count]));
  194.         [self appendToView:textView text:buf];
  195.         sprintf(buf, "Number of properties in each record: %d\n", 
  196.                                                 (pc = [propertyList count]));
  197.         while (--c >= 0) {
  198.               [bind setTo:c];
  199.             sprintf(buf, "Record %d\n", c);
  200.             [self appendToView:textView text:buf];
  201.             [self appendToView:textView text:"------------"];
  202.  
  203.               for (i = 0; i < pc; i++) {
  204.                 prop = [propertyList objectAt:i];
  205.                 sprintf(buf, "%s: %s\t", [prop name],
  206.                 [[bind valueForProperty:prop] stringValue]);
  207.                 [self appendToView:textView text:buf];
  208.                   }
  209.             [self appendToView:textView text:"\n"];
  210.         }
  211.      }
  212.  
  213.     return self;
  214. }
  215.  
  216.  
  217. - appendToView:(id) scrollView text:(const char *)newText
  218. {
  219.     int currentLength = [[scrollView docView] textLength];
  220.     [[scrollView docView] setSel:currentLength :currentLength];
  221.     [[scrollView docView] replaceSel:newText];
  222.     [[scrollView docView] scrollSelToVisible];
  223.     return self;
  224. }
  225.  
  226. /* DBFetchGroup delegate methods */
  227.  
  228. /*
  229.  * This method is called at each SELECT operation.
  230.  */
  231. - fetchGroupWillFetch:fetchGroup
  232. {
  233.     [dbRecordList addRetrieveOrder:recordOrder for:sortProp];
  234.     return self;
  235. }
  236.  
  237. /*
  238.  * This method is called at each INSERT operation.
  239.  */
  240.  
  241. - fetchGroup:fetchGroup didInsertRecordAt:(int)index
  242. {
  243.         /* Fill in the record fields before inserting the new record */
  244.     [self fillNewRecordAt:index];
  245.     return self;
  246. }
  247.  
  248.  
  249. /* 
  250.  * This delegate method is called at each SAVE ope!1on.
  251.  */
  252. - fetchGroupDidSave:fetchGroup
  253. {
  254.     [self clearData];
  255.     return self;
  256. }
  257.  
  258. /* 
  259.  * This binder delegate method is called at each SELECT operation so that 
  260.  * the proper qualifier is used.
  261.  */
  262.  
  263. - (BOOL)binderWillSelect:aBinder
  264. {
  265.   [aBinder setQualifier:dbQualifier];
  266.   return YES;
  267. }
  268.  
  269. /* checkInputRecord
  270.  * Check if any input field is empty.
  271.  */
  272. - checkInputRecord:sender
  273. {
  274.     int    i;
  275.     const char *inputStr;
  276.         
  277.     for ( i = 0; i < 9; i++ ) {
  278.          inputStr = (const char *)[formMatrix stringValueAt:i];
  279.             /* If the string is empty, abort the operation */
  280.         if  ( inputStr == NULL){
  281.             NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  282.             return nil;
  283.             }
  284.     }
  285.          return self;
  286. }
  287.  
  288. /* fillNewRecordAt:(int) index
  289.  * Method used for INSERT operation 
  290.  * Get the user input from the form cells. 
  291.  */
  292. - fillNewRecordAt:(int)index
  293. {
  294.     const char *inputString;
  295.     int    contractNum;
  296.         
  297.             /* set last name */        
  298.     inputString = (const char *)[formMatrix stringValueAt:0];
  299.     [aValue setStringValue:inputString];
  300.     [dbRecordList setValue:aValue 
  301.                 forProperty:[[dbModule entity] propertyNamed:"lastName"]
  302.                 at:index];    
  303.                 
  304.         /* set first name */
  305.     inputString = (const char *)[formMatrix stringValueAt:1];
  306.     [aValue setStringValue:(const char *)inputString];
  307.     [dbRecordList setValue: aValue
  308.                 forProperty: [[dbModule entity] propertyNamed:"firstName"]
  309.                 at:index];
  310.                 
  311.         /* get the ssn or author id */
  312.      inputString = (const char *)[formMatrix stringValueAt:2];
  313.     [aValue setStringValue:inputString];
  314.     [dbRecordList setValue:aValue 
  315.                 forProperty:[[dbModule entity] propertyNamed:"authorID"]
  316.                 at:index];
  317.     strcpy( newAuthorID, inputString);
  318.             
  319.             /* set address */
  320.     inputString = (const char *)[formMatrix stringValueAt:3];
  321.     [aValue setStringValue: inputString];
  322.     [dbRecordList setValue: aValue
  323.                 forProperty:[[dbModule entity] propertyNamed:"address"]
  324.                 at:index];
  325.  
  326.             /* set city name */
  327.     inputString = (const char *)[formMatrix stringValueAt:4];
  328.     [aValue setStringValue: inputString];
  329.     [dbRecordList setValue: aValue
  330.             forProperty:[[dbModule entity] propertyNamed:"city"]
  331.             at:index];
  332.  
  333.             /* set state */
  334.     inputString = (const char *)[formMatrix stringValueAt:5];
  335.     [aValue setStringValue: inputString];
  336.     [dbRecordList setValue: aValue
  337.             forProperty:[[dbModule entity] propertyNamed:"state"]
  338.             at:index];
  339.  
  340.             /* set zip code */
  341.     inputString = (const!1r *)[formMatrix stringValueAt:6];
  342.     [aValue setStringValue: inputString];
  343.     [dbRecordList setValue: aValue
  344.             forProperty:[[dbModule entity] propertyNamed:"zipCode"]
  345.             at:index ];
  346.     
  347.             /* set phone number */
  348.     inputString = (const char *)[formMatrix stringValueAt:7];
  349.     [aValue setStringValue: inputString];
  350.     [dbRecordList setValue:aValue
  351.                 forProperty:[[dbModule entity] propertyNamed:"phone"]
  352.                 at:index];
  353.     
  354.             /* set contract number */
  355.     contractNum = [formMatrix intValueAt:8];
  356.     [aValue setIntValue:contractNum];
  357.     [dbRecordList setValue: aValue
  358.                 forProperty:[[dbModule entity] propertyNamed:"contract"]
  359.                 at:index];
  360.  
  361.     return self;
  362. }
  363.  
  364.  
  365. /* Clear the form cells after each SAVE operation to avoid creating
  366.  * duplicate records.
  367.  */
  368. - clearData
  369. {
  370.     int i;
  371.     
  372.     for (i = 0; i < 9; i++)
  373.         [formMatrix setStringValue:""at:i];
  374.     return self;
  375. }
  376.  
  377. @end
  378.  
  379.