home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Snippets / EMBL Search / Sources / query.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-04  |  22.9 KB  |  1,024 lines  |  [TEXT/KAHL]

  1. /*
  2. *********************************************************************
  3. *    
  4. *    Query.c
  5. *    Handling of query screen
  6. *
  7. *    Rainer Fuchs
  8. *    EMBL Data Library
  9. *    Postfach 10.2209
  10. *    D-6900 Heidelberg, FRG
  11. *    E-mail: fuchs@embl-heidelberg.de
  12. *
  13. *    Copyright © 1992 EMBL Data Library
  14. *        
  15. **********************************************************************
  16. *    
  17. */ 
  18.  
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include "EMBL-Search.h"
  22. #include "EMBL-Search.rsrc.h"
  23.  
  24. /*
  25. ******************************* Prototypes ***************************
  26. */
  27.  
  28. #include "query.h"
  29. #include "util.h"
  30. #include "menus.h"
  31. #include "events.h"
  32. #include "window.h"
  33. #include "pstr.h"
  34. #include "browse.h"
  35. #include "search.h"
  36. #include "hitstorage.h"
  37. #include "results.h"
  38.  
  39. static Boolean NewQueryRec(QueryHdl *new);
  40. static Boolean ReadQuery(StringPtr fName, short vRefNum, QueryHdl *queryHdlP);
  41. static void HandleQueryEvt(DialogPtr myDialog, short itemHit);
  42. static void SetBoolTxt(DialogPtr myDialog, short firstItem, short gBooleanOp);
  43. static short DB2Button(QueryHdl queryHdl);
  44. static short Button2DB(short theItem);
  45. static short Bool2Button(QueryHdl queryHdl);
  46. static short Button2Bool(short theItem);
  47. static pascal void DrawQueryUsrItems(WindowPtr wPtr, short itemNo);
  48. static void DrawTriangle(Rect *boxPtr);
  49. static void HandlePopUpMenu(DialogPtr myDialog, short itemHit, QueryHdl queryHdl);
  50. static void ExecuteQuery(WDPtr wdp);
  51. static void CheckSqDBComp(DialogPtr myDialog, QueryHdl queryHdl);
  52.  
  53.  
  54. /*
  55. ********************************* Globals *****************************
  56. */
  57.  
  58. extern DBInfo        gDBInfo[DB_NUM];
  59. extern char            gError[256];
  60. extern WDRec        gWindows[MAXWIN];
  61. extern Rect            gQueryWinRect;
  62. extern Boolean        gInBackground;
  63. extern MenuHandle    gMenu[MENUNR];
  64. extern short        gResNo;
  65.  
  66. short gQueryNo;
  67.  
  68.  
  69. /**************************************
  70. *    Handle events in query window. Returns TRUE, if event was handled, or FALSE
  71. *    if event will have to be handled by some other routine.
  72. */
  73.  
  74. Boolean DoQueryEvt(EventRecord theEvent)
  75. {
  76.     DialogPtr myDialog;
  77.     short itemHit;
  78.     Boolean isHandled = FALSE;
  79.     
  80.     /* Do necessary pre-processing before we call DialogSelect */
  81.     
  82.       switch (theEvent.what) {
  83.         case keyDown:
  84.         case autoKey:
  85.             MaintainMenus();
  86.             if (theEvent.modifiers & cmdKey) {
  87.                 DoEvent(theEvent);
  88.                 isHandled = TRUE;
  89.             }
  90.             else {
  91.                 switch(theEvent.message & charCodeMask) {
  92.                     case 0x09:    /* tab */
  93.                     case 0x1E:    /* up arrow */
  94.                     case 0x1F:    /* down arrow */
  95.                     case 0x1C:    /* left arrow */
  96.                     case 0x1D:    /* right arrow */
  97.                         break;
  98.                     case 0x03:    /* enter */
  99.                     case 0x0D:    /* return */
  100.                         ExecuteQuery((WDPtr)FrontWindow());
  101.                         isHandled = TRUE;
  102.                         break;
  103.                 }
  104.             }
  105.             break;
  106.     } /* end switch */
  107.  
  108.     if(!isHandled) {
  109.         if(isHandled = DialogSelect(&theEvent,&myDialog,&itemHit)) {
  110.             ((WDPtr)myDialog)->dirty = TRUE; /* not absolutely correct :-( */
  111.             HandleQueryEvt(myDialog,itemHit);
  112.         }
  113.     }
  114.     
  115.     return(isHandled);
  116. }
  117.  
  118.  
  119. /**************************************
  120. *    Open a new query window, do necessary initialisation
  121. */
  122.  
  123. void NewQuery()
  124. {
  125.     QueryHdl    queryHdl;
  126.     Str255    title;
  127.     char        temp[256];
  128.     short        w;
  129.     WDPtr        wdp;
  130.     
  131.     if( (w=GetFreeWindow()) == -1 ) {
  132.         ErrorMsg(ERR_MAXWIN);
  133.         return;
  134.     }
  135.     else
  136.         wdp = &gWindows[w];
  137.         
  138.     if( !NewQueryBlock(DB_EMBL, &queryHdl, BOOLEAN_AND) ) {
  139.         ErrorMsg(ERR_MEMORY);
  140.         return;
  141.     }
  142.  
  143.     /* Open window */
  144.     GetIndString(title,OTHERS,QUERYTITLE);
  145.     sprintf(temp,PtoCstr(title),++gQueryNo);
  146.         
  147.     if( !NewQueryWindow(w,wdp,queryHdl, CtoPstr((char *)temp)) ) {
  148.         DisposHandle((Handle)queryHdl);
  149.     } /* end if !NewResultsWindow() */
  150. }        
  151.  
  152.  
  153. /**************************************
  154. *    Allocates a new query record and initialises it
  155. *    Return values:
  156. *    Return value:    TRUE, if successful
  157. *                        FALSE, if error occurred
  158. *    Side effect:    Handle to new query record
  159. */
  160.  
  161. Boolean NewQueryBlock(short dbcode, QueryHdl *new, short gBooleanOp)
  162. {
  163.     QueryPtr queryPtr;
  164.     short i;
  165.     
  166.     /* Allocate memory for query record */
  167.     if ( !NewQueryRec(new) )
  168.         return( FALSE );
  169.     
  170.     /* Get a pointer to it */
  171.     LockHandleHigh((Handle)*new);
  172.     queryPtr = (QueryPtr)**new;
  173.  
  174.     /* Init fields */
  175.     queryPtr->magic = TickCount();
  176.     queryPtr->dbcode = dbcode;
  177.     strcpy( queryPtr->DBRelNum,gDBInfo[dbcode].DBRelNum );
  178.     queryPtr->gBooleanOp = gBooleanOp;
  179.     for(i=0;i<MAXSUBQRY;++i) {
  180.         *(queryPtr->subQuery[i].text) = EOS;
  181.         queryPtr->subQuery[i].field = ENAME_QRY;
  182.     }
  183.  
  184.     HUnlock((Handle)*new);
  185.     return(TRUE);
  186. }
  187.  
  188. /**************************************
  189. *    Allocates relocatable memory block for query record
  190. *    Return value:    TRUE, if successful
  191. *                        FALSE, if error occurred
  192. *    Side-effect:    Handle to this block
  193. */
  194.  
  195. static Boolean NewQueryRec(QueryHdl *new)
  196. {
  197.     *new = (QueryHdl)NewHandleClear(sizeof(QueryRec));
  198.     return( *new != NULL );
  199. }
  200.  
  201.  
  202. /**************************************
  203. *    Open a new query window
  204. *    Return value:    TRUE, if successful
  205. *                        FALSE, if an error occurred
  206. */
  207.  
  208. Boolean NewQueryWindow(short w,WDPtr wdp, QueryHdl queryHdl, StringPtr title)
  209. {
  210.     register short i;
  211.     Rect            tempRect;
  212.     DialogPtr    dPtr;
  213.     DialogTHndl    myHandle;
  214.     SignedByte    oldState;
  215.  
  216.     if( queryHdl == NULL || wdp == NULL)
  217.         return(FALSE);
  218.         
  219.     oldState = MyHLock((Handle)queryHdl);
  220.         
  221.     myHandle=(DialogTHndl)GetResource('DLOG',QUERY_DLG);
  222.     if(myHandle == NULL) return(FALSE);
  223.     (**myHandle).boundsRect = gQueryWinRect;
  224.     AdjustPosition(w,&(**myHandle).boundsRect);
  225.     
  226.     dPtr = GetNewDialog(QUERY_DLG,wdp,(void *)-1);
  227.  
  228.     /* anchor query record */
  229.     wdp->userHandle = (Handle)queryHdl;
  230.                 
  231.     SetWTitle((WindowPtr)wdp,title);
  232.  
  233.     SelRadioButton(dPtr,QRY_EMBL_BTN,2,DB2Button(queryHdl));
  234.     SelRadioButton(dPtr,QRY_AND_BTN,2,Bool2Button(queryHdl));
  235.     SetBoolTxt(dPtr,QRY_BOOLSTR1+1,(**queryHdl).gBooleanOp);
  236.  
  237.     InstallUserItem(dPtr,QRY_USRITEM,OK,DrawOKBoxRect);
  238.     for(i=0;i<MAXSUBQRY;++i)
  239.         InstallUserItem(dPtr,QRY_POPUP1+i,-1,DrawQueryUsrItems);
  240.  
  241.     for(i = 0; i< MAXSUBQRY; ++i)
  242.         SetDlgText(dPtr,QRY_SUBQRY1 + i,(**queryHdl).subQuery[i].text);
  243.  
  244.     pstrcpy(wdp->fName,title);
  245.     wdp->vRefNum = 0;
  246.     wdp->dirty = TRUE;
  247.     wdp->inited = FALSE;
  248.     wdp->inUse = TRUE;
  249.     
  250.     AddWindowToMenu(title);
  251.     
  252.     HSetState((Handle)queryHdl,oldState);
  253.     
  254.     ShowWindow(dPtr);
  255.     SetPort(dPtr);
  256.     return(TRUE);
  257. }
  258.  
  259.  
  260. /**************************************
  261. *    Close query window and dispose of query record
  262. */
  263.  
  264. void DisposeQuery(WDPtr wdp)
  265. {
  266.     if (wdp == NULL || ((WindowPeek)wdp)->windowKind != queryW)
  267.         return;
  268.         
  269.     if (wdp->inUse)
  270.         CloseDialog((DialogPtr)wdp);
  271.         
  272.     if(wdp->userHandle) {
  273.         DisposHandle((Handle)wdp->userHandle);
  274.     }
  275.             
  276.     ClearWindowRec(wdp);
  277. }
  278.  
  279. /**************************************
  280. *    Updates query record before we duplicate or start a query.
  281. */
  282.  
  283. void UpdateQueryRec(WDPtr wdp)
  284. {
  285.     QueryHdl        queryHdl;
  286.     SignedByte    oldState;
  287.    short            itemType;
  288.    Handle        item;
  289.    Rect            box;
  290.    Str255        text;
  291.    register short i;
  292.     
  293.     if (wdp == NULL || ((WindowPeek)wdp)->windowKind != queryW)
  294.         return;
  295.         
  296.     if((queryHdl = (QueryHdl)wdp->userHandle) == NULL)
  297.         return;
  298.         
  299.     oldState = MyHLock((Handle)queryHdl);
  300.     
  301.     for(i = 0; i< MAXSUBQRY; ++i) {
  302.        GetDItem((DialogPtr)wdp, QRY_SUBQRY1 + i,&itemType,&item,&box);
  303.        GetIText(item,text);
  304.        pstrcpy((**queryHdl).subQuery[i].text,text);
  305.     }
  306.     
  307.     (**queryHdl).magic = TickCount();
  308.     
  309.     HSetState((Handle)queryHdl,oldState);
  310. }
  311.  
  312.  
  313. /**************************************
  314. *    Duplicate a query to a new window
  315. */
  316.  
  317. void DuplicateQuery(WDPtr wdp)
  318. {
  319.     SignedByte    oldState;
  320.     Str255        title;
  321.     char            temp[256];
  322.     QueryHdl        queryHdl, newQueryHdl;
  323.     short            w;
  324.     WDPtr            queryWdp;
  325.     
  326.     if(wdp == NULL || ((WindowPeek)wdp)->windowKind != dialogKind)
  327.         return;
  328.     
  329.     if((queryHdl = (QueryHdl)wdp->userHandle) == NULL)
  330.         return;
  331.  
  332.     if( (w=GetFreeWindow()) == -1 ) {
  333.         ErrorMsg(ERR_MAXWIN);
  334.         return;
  335.     }
  336.     else
  337.         queryWdp = &gWindows[w];
  338.             
  339.     oldState = MyHLock((Handle)queryHdl);
  340.     
  341.     /* update query record */
  342.     UpdateQueryRec(wdp);
  343.  
  344.     /* copy query record */
  345.     newQueryHdl = queryHdl;
  346.     if(HandToHand((Handle *)&newQueryHdl) != noErr) {
  347.         ErrorMsg(ERR_MEMORY);
  348.     }
  349.     
  350.     /* Open window */
  351.     GetIndString(title,OTHERS,QUERYTITLE);
  352.     sprintf(temp,PtoCstr(title),++gQueryNo);
  353.         
  354.     if( !NewQueryWindow(w,queryWdp,newQueryHdl, CtoPstr((char *)temp)) ) {
  355.         DisposHandle((Handle)newQueryHdl);
  356.     }
  357.  
  358.     HSetState((Handle)queryHdl,oldState);
  359. }
  360.  
  361.  
  362. /**************************************
  363. *    Communication with user to load old query from disk
  364. */
  365.  
  366. void OpenQuery()
  367. {
  368.     Point         where;
  369.     SFTypeList    myTypes;
  370.     SFReply         reply;
  371.     short            w;
  372.     
  373.     if( (w=GetFreeWindow() ) == -1 ) {
  374.         ErrorMsg(ERR_MAXWIN);
  375.         return;
  376.     }
  377.  
  378.     /* Get file name */
  379.     HandleActivates(FrontWindow(),0);
  380.     CenterSFDlg(getDlgID,&where);
  381.     myTypes[0] = kQryFileType;
  382.     SFGetFile(where,"\p",NULL,1,myTypes,NULL,&reply);     /* ask for file name */
  383.  
  384.    if (reply.good == TRUE)    {
  385.        StartWaitCursor();
  386.        LoadQuery(w,reply.fName,reply.vRefNum);
  387.           InitCursor();
  388.    }
  389. }
  390.  
  391. /**************************************
  392. *    Load queries, check for database version and open window
  393. *    ( also called from CheckApp() )
  394. */
  395.  
  396. Boolean LoadQuery(short w,StringPtr fName, short vRefNum)
  397. {
  398.     Str255        temp;
  399.     WDPtr            wdp;
  400.     QueryHdl        queryHdl;
  401.     short            dbcode;
  402.     short            field;
  403.     register short i;
  404.           
  405.    /* Read in resources from file */
  406.    if(ReadQuery(fName,vRefNum,&queryHdl)) {
  407.         wdp = &gWindows[w];
  408.  
  409.        /* Update database version  */
  410.          dbcode = (**queryHdl).dbcode;
  411.          strcpy((**queryHdl).DBRelNum,gDBInfo[dbcode].DBRelNum );
  412.  
  413.         /* here we have to check for non-existing values in queryField.field,
  414.             eg if a query is used with an older CD-ROM */
  415.             
  416.         for(i = 0; i<MAXSUBQRY; ++i) {
  417.             field = (**queryHdl).subQuery[i].field;
  418.             
  419.             switch(field) {
  420.                 case ENAME_QRY:    /* must always exist */
  421.                     break;
  422.                 case ACCNUM_QRY:
  423.                     if(gDBInfo[dbcode].actrg_recsize == 0) {
  424.                         DisposHandle((Handle)queryHdl);
  425.                         return(ErrorMsg(ERR_INCQUERY));
  426.                     }
  427.                     break;
  428.                 case KEYWORD_QRY:
  429.                     break;
  430.                     if(gDBInfo[dbcode].kwtrg_recsize == 0) {
  431.                         DisposHandle((Handle)queryHdl);
  432.                         return(ErrorMsg(ERR_INCQUERY));
  433.                     }
  434.                     break;
  435.                 case FREETEXT_QRY:
  436.                     if(gDBInfo[dbcode].texttrg_recsize == 0) {
  437.                         DisposHandle((Handle)queryHdl);
  438.                         return(ErrorMsg(ERR_INCQUERY));
  439.                     }
  440.                     break;
  441.                 case AUTHOR_QRY:
  442.                     if(gDBInfo[dbcode].authortrg_recsize == 0) {
  443.                         DisposHandle((Handle)queryHdl);
  444.                         return(ErrorMsg(ERR_INCQUERY));
  445.                     }
  446.                     break;
  447.                 case TAXON_QRY:
  448.                     if(gDBInfo[dbcode].taxontrg_recsize == 0) {
  449.                         DisposHandle((Handle)queryHdl);
  450.                         return(ErrorMsg(ERR_INCQUERY));
  451.                     }
  452.                     break;
  453.                 default:
  454.                     DisposHandle((Handle)queryHdl);
  455.                     return(ErrorMsg(ERR_INCQUERY));
  456.                     break;                    
  457.             }
  458.         }
  459.  
  460.         if( !NewQueryWindow(w,wdp,queryHdl,fName) )
  461.             DisposeQuery(wdp);
  462.  
  463.         wdp->vRefNum = vRefNum;
  464.         wdp->dirty = FALSE;
  465.         wdp->inited = TRUE;
  466.         return(TRUE);
  467.     }
  468.     else return(FALSE);
  469. }
  470.  
  471. /**************************************
  472. *    Read query file from disk
  473. *    Return value:    TRUE, if successful
  474. *                        FALSE, if an error occurred
  475. */
  476.  
  477. static Boolean ReadQuery(StringPtr fName, short vRefNum,QueryHdl *queryHdlP)
  478. {
  479.     short            oldVRefNum;
  480.     Str255        volName;
  481.     short            refNum;
  482.     OSErr            err;
  483.     Boolean        ret=FALSE;            /* We assume failure */
  484.     short            curResFile;
  485.     
  486.     /* set default directory */
  487.     GetVol(volName,&oldVRefNum);
  488.     SetVol(NULL,vRefNum);
  489.     
  490.     /* store refnum of current resource file */
  491.     curResFile = CurResFile();
  492.     
  493.     /* Open resource file */
  494.     if( (refNum=OpenResFile(fName)) == -1) {
  495.         sprintf(gError,LoadErrorStr(ERR_OPENRES,FALSE),
  496.                     PtoCstr(fName),ResError());
  497.         CtoPstr((char *)fName);
  498.         ErrorMsg(0);
  499.         goto end;
  500.     }
  501.  
  502.     /* Make it active resource file and read necessary resources */
  503.     UseResFile(refNum);    
  504.     *queryHdlP = (QueryHdl)Get1Resource(kQueryRsrcType,kStdRsrc);
  505.     if( (err=ResError()) != noErr ) {
  506.         CloseResFile(refNum);
  507.         sprintf(gError,LoadErrorStr(ERR_READRES,FALSE),
  508.                     PtoCstr(fName),err);
  509.         CtoPstr((char *)fName);
  510.         ErrorMsg(0);
  511.         goto end;
  512.     }
  513.     
  514.     /* Detach resources and close file */
  515.     DetachResource((Handle)*queryHdlP);
  516.     CloseResFile(refNum);
  517.     ret=TRUE;
  518.  
  519. end:
  520.     /* reset old values */
  521.    UseResFile(curResFile);
  522.     SetVol(NULL,oldVRefNum);
  523.     return(ret);
  524. }
  525.  
  526.  
  527. /**************************************
  528. *    Handle mouse clicks in query dialogs
  529. */
  530.  
  531. static void HandleQueryEvt(DialogPtr myDialog, short itemHit)
  532. {
  533.     WDPtr            wdp = (WDPtr)myDialog;
  534.     QueryHdl        queryHdl;
  535.     SignedByte    oldState;
  536.     Str255        oldText,newText;
  537.     short            which,i;
  538.    short            itemType;
  539.    Handle        item;
  540.    Rect            box;
  541.     GrafPtr        savePort;
  542.     
  543.     if(wdp == NULL || ((WindowPeek)myDialog)->windowKind != dialogKind)
  544.         return;
  545.     
  546.     if((queryHdl = (QueryHdl)wdp->userHandle) == NULL)
  547.         return;
  548.         
  549.     oldState = MyHLock((Handle)queryHdl);
  550.         
  551.     savePort = ChangePort(myDialog);
  552.     
  553.     switch(itemHit) {
  554.         case QRY_EMBL_BTN:
  555.         case QRY_SWISS_BTN:
  556.             SelRadioButton(myDialog,QRY_EMBL_BTN,2,itemHit);
  557.             (**queryHdl).dbcode = Button2DB(itemHit);
  558.             CheckSqDBComp(myDialog, queryHdl);
  559.             break;
  560.         case QRY_AND_BTN:
  561.         case QRY_OR_BTN:
  562.             SelRadioButton(myDialog,QRY_AND_BTN,2,itemHit);
  563.             (**queryHdl).gBooleanOp = Button2Bool(itemHit);
  564.             SetBoolTxt(myDialog,QRY_BOOLSTR1+1,(**queryHdl).gBooleanOp);
  565.             break;
  566.         case QRY_POPUP1:
  567.         case QRY_POPUP1 + 1:
  568.         case QRY_POPUP1 + 2:
  569.         case QRY_POPUP1 + 3:
  570.         case QRY_POPUP1 + 4:
  571.             HandlePopUpMenu(myDialog,itemHit, queryHdl);
  572.             break;
  573.         case QRY_BROWSEBTN:            
  574.             which = ((DialogPeek)myDialog)->editField + 1 - QRY_SUBQRY1;
  575.             if(BrowseIndex((**queryHdl).dbcode,(**queryHdl).subQuery[which].field, newText)) {
  576.                 DlgDelete(myDialog);        /* in case the user had selected some text before
  577.                                                     accessing the index */
  578.                 GetDlgText(myDialog,QRY_SUBQRY1 + which,oldText);
  579.                 if( (u_short)*oldText + (u_short)*newText <= 255) {
  580.                     pstrcat(oldText,newText);
  581.                     SetDlgText(myDialog,QRY_SUBQRY1 + which,oldText);
  582.                     SelIText(myDialog,QRY_SUBQRY1 + which,32767,32767);
  583.                 }
  584.             }
  585.             break;            
  586.         case OK:
  587.             ExecuteQuery(wdp);
  588.             break;
  589.         case QRY_CLEARBTN:
  590.             for(i=0;i<MAXSUBQRY;++i) {
  591.                 *((**queryHdl).subQuery[i].text) = EOS;
  592.                 SetDlgText(myDialog,QRY_SUBQRY1 + i,(**queryHdl).subQuery[i].text);
  593.                 if((**queryHdl).subQuery[i].field != ENAME_QRY) {
  594.                     (**queryHdl).subQuery[i].field = ENAME_QRY;
  595.                     GetDItem(myDialog,QRY_POPUP1+i,&itemType,&item,&box);
  596.                     InvalRect(&box);
  597.                 }
  598.             }
  599.  
  600.             wdp->dirty = TRUE;
  601.             break;
  602.     }
  603.  
  604.     SetPort(savePort);
  605.     HSetState((Handle)queryHdl,oldState);
  606. }
  607.  
  608. /**************************************
  609. *    Set the text which shows current boolean operation between subqueries
  610. */
  611.  
  612. static void SetBoolTxt(DialogPtr myDialog, short firstItem, short gBooleanOp)
  613. {
  614.     register short i;
  615.     StringPtr text;
  616.     
  617.     switch(gBooleanOp) {
  618.         case BOOLEAN_AND: text = "\pAND";
  619.             break;
  620.         case BOOLEAN_OR: text = "\pOR";
  621.             break;
  622.     }
  623.     
  624.     for(i=0;i<MAXSUBQRY-1;++i)
  625.         SetDlgText(myDialog,firstItem+i,text);
  626. }
  627.  
  628.  
  629. /**************************************
  630. *    Find dialog button which corresponds to a given dbcode
  631. */
  632.  
  633. static short DB2Button(QueryHdl queryHdl)
  634. {
  635.     short button;
  636.     
  637.     switch((**queryHdl).dbcode) {
  638.         case DB_EMBL:
  639.             button = QRY_EMBL_BTN;
  640.             break;
  641.         case DB_SWISS:
  642.             button = QRY_SWISS_BTN;
  643.             break;
  644.     }
  645.     return(button);
  646. }
  647.  
  648. /**************************************
  649. *    Find dbcode which corresponds to a given dialog button
  650. */
  651.  
  652. static short Button2DB(short theItem)
  653. {
  654.     short dbcode;
  655.     
  656.     switch(theItem) {
  657.         case QRY_EMBL_BTN:
  658.             dbcode = DB_EMBL;
  659.             break;
  660.         case QRY_SWISS_BTN:
  661.             dbcode = DB_SWISS;
  662.             break;
  663.     }
  664.     return(dbcode);
  665. }
  666.  
  667. /**************************************
  668. *    Find dialog button which corresponds to a given boolean operation
  669. */
  670.  
  671. static short Bool2Button(QueryHdl queryHdl)
  672. {
  673.     short button;
  674.     
  675.     switch((**queryHdl).gBooleanOp) {
  676.         case BOOLEAN_AND:
  677.             button = QRY_AND_BTN;
  678.             break;
  679.         case BOOLEAN_OR:
  680.             button = QRY_OR_BTN;
  681.             break;
  682.     }
  683.     return(button);
  684. }
  685.  
  686. /**************************************
  687. *    Find boolean operation which corresponds to a given dialog button
  688. */
  689.  
  690. static short Button2Bool(short theItem)
  691. {
  692.     short boolOp;
  693.     
  694.     switch(theItem) {
  695.         case QRY_AND_BTN:
  696.             boolOp = BOOLEAN_AND;
  697.             break;
  698.         case QRY_OR_BTN:
  699.             boolOp = BOOLEAN_OR;
  700.             break;
  701.     }
  702.     return(boolOp);
  703. }
  704.  
  705. /**************************************
  706. *    Draws a pop-up menu box
  707. */
  708.  
  709. static pascal void DrawQueryUsrItems(WindowPtr wPtr, short itemNo)
  710. {
  711.    short            itemType;
  712.    Handle        item;
  713.    Rect            box;
  714.    Str255         text;
  715.    QueryHdl        queryHdl;
  716.    SignedByte    oldState;
  717.    short            subquery;
  718.    
  719.     if((queryHdl = (QueryHdl)((WDPtr)wPtr)->userHandle) == NULL)
  720.         return;
  721.     
  722.     oldState = MyHLock((Handle)queryHdl);
  723.     
  724.     subquery = itemNo - QRY_POPUP1;
  725.  
  726.     /* draw popup-box frame*/
  727.     GetDItem(wPtr,itemNo,&itemType,&item,&box);
  728.     EraseRect(&box);
  729.     InsetRect(&box,-1,-1);
  730.     FrameRect(&box);
  731.     MoveTo(box.left+15,box.bottom-5);
  732.     GetItem (gMenu[POPUP], (**queryHdl).subQuery[subquery].field,text);
  733.    DrawString(text);
  734.     
  735.     /*draw drop shadow */
  736.     MoveTo(box.right,box.top+2);
  737.     LineTo(box.right,box.bottom);
  738.     LineTo(box.left+2,box.bottom);
  739.     
  740.     DrawTriangle(&box);
  741.     
  742.     HSetState((Handle)queryHdl,oldState);
  743. }
  744.  
  745. /**************************************
  746. *    Draws downwards triangle in pull-down menu
  747. */
  748.  
  749. static void DrawTriangle(Rect *boxPtr)
  750. {
  751.     PolyHandle    downArrow;
  752.  
  753.     downArrow = OpenPoly();                                /* build polygon for down-arrow */
  754.         MoveTo(boxPtr->right-3,boxPtr->top+6);        /* location for 16-pixel-high box */
  755.          Line(-12,0);
  756.         Line(6,6);
  757.         Line(6,-6);
  758.     ClosePoly();
  759.     FillPoly(downArrow,black);                            /* and draw arrow */
  760.     KillPoly(downArrow);
  761. }
  762.  
  763.  
  764. /**************************************
  765. *    Handle mouse clicks in pop-up menus
  766. */
  767.  
  768. static void HandlePopUpMenu(DialogPtr myDialog, short itemHit, QueryHdl queryHdl)
  769. {
  770.     short        subquery;
  771.    short        itemType;
  772.    Handle    item;
  773.    Rect        box,popRect,titleRect;
  774.    short        current;
  775.    short        whichItem;
  776.    short        i;
  777.    short        dbcode;
  778.    GrafPtr    savePort;
  779.     
  780.     subquery = itemHit - QRY_POPUP1;
  781.     current = (**queryHdl).subQuery[subquery].field;
  782.     dbcode = (**queryHdl).dbcode;
  783.     
  784.     savePort = ChangePort(myDialog);
  785.    GetDItem(myDialog,itemHit,&itemType,&item,&box);
  786.    popRect = box;
  787.     LocalToGlobal(&TopLeft(popRect));
  788.     LocalToGlobal(&BottomRight(popRect));
  789.     
  790.     GetDItem(myDialog,QRY_IN1 + subquery,&itemType,&item,&titleRect);
  791.     DoInvertRect(&titleRect);
  792.     for(i=1;i<=CountMItems(gMenu[POPUP]);++i) {
  793.         EnableItem(gMenu[POPUP],i);
  794.         SetItemMark(gMenu[POPUP],i,' ');
  795.     }
  796.     SetItemMark(gMenu[POPUP],current,checkMark);
  797.  
  798.     /* Disable query functions not available */
  799.     if(gDBInfo[dbcode].actrg_recsize == 0)
  800.         DisableItem(gMenu[POPUP],ACCNUM_QRY);
  801.     if(gDBInfo[dbcode].kwtrg_recsize == 0)
  802.         DisableItem(gMenu[POPUP],KEYWORD_QRY);
  803.     if(gDBInfo[dbcode].texttrg_recsize == 0)
  804.         DisableItem(gMenu[POPUP],FREETEXT_QRY);
  805.     if(gDBInfo[dbcode].authortrg_recsize == 0)
  806.         DisableItem(gMenu[POPUP],AUTHOR_QRY);
  807.     if(gDBInfo[dbcode].taxontrg_recsize == 0)
  808.         DisableItem(gMenu[POPUP],TAXON_QRY);
  809.         
  810.     whichItem=PopUpMenuSelect(gMenu[POPUP],popRect.top,popRect.left,current);
  811.     if(whichItem=LoWord(whichItem)) {
  812.         (**queryHdl).subQuery[subquery].field = whichItem;
  813.     }
  814.     InvalRect(&box);
  815.     DoInvertRect(&titleRect);
  816.     SetPort(savePort);
  817. }
  818.  
  819.  
  820. /**************************************
  821. *    Execute a query
  822. */
  823.  
  824. static void ExecuteQuery(WDPtr wdp)
  825. {
  826.     register short i;
  827.     SignedByte    oldState;
  828.     Str255        text,title;
  829.     char            temp[256];
  830.     short            field;
  831.     short            boolOp;
  832.     short            dbcode;
  833.     HitmapHdl    masterHmHdl, newHmHdl;
  834.     QueryHdl        queryHdl, newQueryHdl;
  835.     ResultHdl    resHdl;
  836.     short            w;
  837.     WDPtr            resWdp;
  838.     DialogPtr    myDialog;
  839.     
  840.     if(wdp == NULL || ((WindowPeek)wdp)->windowKind != dialogKind)
  841.         return;
  842.     
  843.     if((queryHdl = (QueryHdl)wdp->userHandle) == NULL)
  844.         return;
  845.  
  846.     if( (w=GetFreeWindow()) == -1 ) {
  847.         ErrorMsg(ERR_MAXWIN);
  848.         return;
  849.     }
  850.     else
  851.         resWdp = &gWindows[w];
  852.         
  853.     CenterDA('DLOG',SEARCHWAIT_DLG,50);
  854.     myDialog = GetNewDialog(SEARCHWAIT_DLG,NULL,(WindowPtr) -1);
  855.     if(myDialog) {
  856.         ShowWindow(myDialog);
  857.         DrawDialog(myDialog);
  858.     }
  859.     
  860.     StartWaitCursor();
  861.     
  862.     oldState = MyHLock((Handle)queryHdl);
  863.     
  864.     /* update query record */
  865.     UpdateQueryRec(wdp);
  866.  
  867.     boolOp = (**queryHdl).gBooleanOp;
  868.     dbcode = (**queryHdl).dbcode;
  869.  
  870.     masterHmHdl = NULL;
  871.     
  872.     /* now we handle each subquery */
  873.     for(i=0;i<MAXSUBQRY;++i) {
  874.         pstrcpy(text,(**queryHdl).subQuery[i].text);
  875.         field = (**queryHdl).subQuery[i].field;
  876.         
  877.         /* skip empty fields */
  878.         if(*text == EOS)
  879.             continue;
  880.         
  881.         /* do search */
  882.         newHmHdl = DoSearch(field,text,dbcode);
  883.  
  884.         /* check for success */
  885.         if(newHmHdl == NULL) {
  886.             /* AND requires action */
  887.             if(boolOp == BOOLEAN_AND) {
  888.                 /* if we had found something in a previous subquery, forget it */
  889.                 if(masterHmHdl != NULL) {
  890.                     DisposHandle((Handle)masterHmHdl);
  891.                     masterHmHdl = NULL;
  892.                 }
  893.                 break;    /* stop query */
  894.             }
  895.             else    /* this is an OR, so simply continue */
  896.                 continue;
  897.         }
  898.             
  899.         if(masterHmHdl == NULL)    /* this is first subquery, so we update master handle */
  900.             masterHmHdl = newHmHdl;
  901.         else {    /* for all further subqueries we AND/OR new hitmap with master hitmap */
  902.             switch(boolOp) {
  903.                 case BOOLEAN_AND:
  904.                     AndHitmaps(masterHmHdl,newHmHdl);
  905.                     break;
  906.                 case BOOLEAN_OR:
  907.                     OrHitmaps(masterHmHdl,newHmHdl);
  908.                     break;
  909.             }
  910.             DisposHandle((Handle)newHmHdl);
  911.         }
  912.     }
  913.     
  914.     if(myDialog) DisposDialog(myDialog);
  915.     
  916.     if(masterHmHdl == NULL) {
  917.         ErrorMsg(ERR_NOTFOUND);
  918.     }
  919.     else {
  920.         /* copy query record */
  921.         newQueryHdl = queryHdl;
  922.         if(HandToHand((Handle *)&newQueryHdl) != noErr) {
  923.             ErrorMsg(ERR_MEMORY);
  924.             DisposHandle((Handle)masterHmHdl);
  925.         }
  926.         /* get a new result record and initialise it */
  927.         else {
  928.             if( !InitResultRec(&resHdl,dbcode,masterHmHdl,newQueryHdl) ) {
  929.                 DisposHandle((Handle)masterHmHdl);
  930.                 DisposHandle((Handle)newQueryHdl);
  931.                 ErrorMsg(ERR_MEMORY);
  932.             }
  933.             else {
  934.                  if( (**resHdl).nhits > MAXHITS ) {
  935.                     DisposeResRec(resHdl);
  936.                     ErrorMsg(ERR_MAXHITSEXC);
  937.                 }
  938.                 else if( (**resHdl).nhits == 0 ) {
  939.                     DisposeResRec(resHdl);
  940.                     ErrorMsg(ERR_NOTFOUND);
  941.                 }
  942.                 else {
  943.                     /* Open window */
  944.                     GetIndString(title,OTHERS,RESTITLE);
  945.                     sprintf(temp,PtoCstr(title),++gResNo);
  946.     
  947.                     if( !NewResultWindow(w,resWdp,resHdl, CtoPstr((char *)temp)) ) {
  948.                         DisposeResults(resWdp);
  949.                     } /* end if !NewResultsWindow() */
  950.                 }
  951.             }    /* end else */
  952.         }
  953.     }
  954.  
  955.     InitCursor();
  956.     HSetState((Handle)queryHdl,oldState);
  957. }
  958.  
  959. static void CheckSqDBComp(DialogPtr myDialog, QueryHdl queryHdl)
  960. {
  961.     register short i;
  962.     short            field;
  963.     short            dbcode;
  964.    short            itemType;
  965.    Handle        item;
  966.    Rect            box;
  967.    Boolean        bChanged;
  968.    GrafPtr        savePort;
  969.  
  970.     if(queryHdl == NULL) return;
  971.     dbcode = (**queryHdl).dbcode;
  972.  
  973.     savePort = ChangePort(myDialog);
  974.     /* check each db field for existence */
  975.     for(i = 0; i<MAXSUBQRY; ++i) {
  976.         field = (**queryHdl).subQuery[i].field;
  977.         bChanged = FALSE;
  978.         
  979.         switch(field) {
  980.             case ENAME_QRY:    /* must always exist */
  981.                 break;
  982.             case ACCNUM_QRY:
  983.                 if(gDBInfo[dbcode].actrg_recsize == 0) {
  984.                     (**queryHdl).subQuery[i].field = ENAME_QRY;
  985.                     bChanged = TRUE;
  986.                 }
  987.                 break;
  988.             case KEYWORD_QRY:
  989.                 break;
  990.                 if(gDBInfo[dbcode].kwtrg_recsize == 0) {
  991.                     (**queryHdl).subQuery[i].field = ENAME_QRY;
  992.                     bChanged = TRUE;
  993.                 }
  994.                 break;
  995.             case FREETEXT_QRY:
  996.                 if(gDBInfo[dbcode].texttrg_recsize == 0) {
  997.                     (**queryHdl).subQuery[i].field = ENAME_QRY;
  998.                     bChanged = TRUE;
  999.                 }
  1000.                 break;
  1001.             case AUTHOR_QRY:
  1002.                 if(gDBInfo[dbcode].authortrg_recsize == 0) {
  1003.                     (**queryHdl).subQuery[i].field = ENAME_QRY;
  1004.                     bChanged = TRUE;
  1005.                 }
  1006.                 break;
  1007.             case TAXON_QRY:
  1008.                 if(gDBInfo[dbcode].taxontrg_recsize == 0) {
  1009.                     (**queryHdl).subQuery[i].field = ENAME_QRY;
  1010.                     bChanged = TRUE;
  1011.                 }
  1012.                 break;
  1013.             default:
  1014.                 (**queryHdl).subQuery[i].field = ENAME_QRY;
  1015.                 bChanged = TRUE;
  1016.                 break;                    
  1017.         }
  1018.         if(bChanged) {
  1019.             GetDItem(myDialog,QRY_POPUP1+i,&itemType,&item,&box);
  1020.             InvalRect(&box);
  1021.         }
  1022.     }
  1023.     SetPort(savePort);
  1024. }