NCBI C Toolkit Cross Reference

C/desktop/e2trmlst.c


  1 /*   e2trmlst.c
  2 * ===========================================================================
  3 *
  4 *                            PUBLIC DOMAIN NOTICE
  5 *            National Center for Biotechnology Information (NCBI)
  6 *
  7 *  This software/database is a "United States Government Work" under the
  8 *  terms of the United States Copyright Act.  It was written as part of
  9 *  the author's official duties as a United States Government employee and
 10 *  thus cannot be copyrighted.  This software/database is freely available
 11 *  to the public for use. The National Library of Medicine and the U.S.
 12 *  Government do not place any restriction on its use or reproduction.
 13 *  We would, however, appreciate having the NCBI and the author cited in
 14 *  any work or product based on this material
 15 *
 16 *  Although all reasonable efforts have been taken to ensure the accuracy
 17 *  and reliability of the software and data, the NLM and the U.S.
 18 *  Government do not and cannot warrant the performance or results that
 19 *  may be obtained by using this software or data. The NLM and the U.S.
 20 *  Government disclaim all warranties, express or implied, including
 21 *  warranties of performance, merchantability or fitness for any particular
 22 *  purpose.
 23 *
 24 * ===========================================================================
 25 *
 26 * File Name:  e2trmlst.c
 27 *
 28 * Author:  Jonathan Kans, Greg Schuler, Jonathan Epstein, Tim Ford
 29 *
 30 * Version Creation Date:   10/30/01
 31 *
 32 * $Revision: 6.44 $
 33 *
 34 * File Description: 
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 *
 39 * ==========================================================================
 40 */
 41 
 42 #include <vibrant.h>
 43 #include <document.h>
 44 #include <asn.h>
 45 #include <ent2api.h>
 46 #include <urlquery.h>
 47 #include <dlogutil.h>
 48 #include <medview.h>
 49 #include <bspview.h>
 50 #include <accutils.h>
 51 
 52 #include <entrez2.h>
 53 
 54 /*-------------------*/
 55 /* Defined constants */
 56 /*-------------------*/
 57 
 58 #define MAX_TAXONOMY_TREE_DEPTH  1024
 59 #define TL_TERM_DELIMITER        ':'
 60 #define E2_STR_BUFF_SIZE         256
 61 #define E2_EXPLODE               FALSE
 62 #define E2_DO_NOT_EXPLODE        TRUE
 63 #define E2_TRANSLATE             FALSE
 64 #define E2_DO_NOT_TRANSLATE      TRUE
 65 #define E2_TERM_COL              1
 66 #define E2_COUNT_COL             2
 67 #define E2_LIST_MODIFIED         TRUE
 68 #define E2_LIST_NOT_MODIFIED     FALSE
 69 
 70 #define MAX_MODES         11
 71 
 72 #define STATE_OFF         0
 73 #define STATE_ON          1
 74 
 75 #define E2_RANGE_FROM     1
 76 #define E2_RANGE_TO       2
 77 
 78 #define GROUP_NONE        0
 79 #define GROUP_SINGLE      1
 80 #define GROUP_FIRST       2
 81 #define GROUP_MIDDLE      3
 82 #define GROUP_LAST        4
 83 
 84 #define TERMLIST_OPERATOR             2
 85 #define TERMLIST_TERM                 3
 86 
 87 #define ADV_QUERY_INVALID_STATE       0
 88 #define ADV_QUERY_EVALUATE_STATE      1
 89 #define ADV_QUERY_RETRIEVE_STATE      2
 90 
 91 #define AVAIL_WINDOW_ROWS             7
 92 #define ADV_TEXT_MAX_LENGTH           8192
 93 #define ADV_TEXT_WIDTH                20
 94 #define ADV_TEXT_HEIGHT               7
 95 
 96 #define LEXCHAR_LPAREN                1
 97 #define LEXCHAR_RPAREN                2
 98 #define LEXCHAR_LBRACKET              3
 99 #define LEXCHAR_RBRACKET              4
100 #define LEXCHAR_QUOTE                 5
101 #define LEXCHAR_AND                   6
102 #define LEXCHAR_OR                    7
103 #define LEXCHAR_NOT                   8
104 #define LEXCHAR_COMMA                 9
105 #define LEXCHAR_ATSIGN               10
106 #define LEXCHAR_BACKSLASH            11
107 #define LEXCHAR_WHITESPACE           12
108 #define LEXCHAR_SEMICOLON            13
109 #define LEXCHAR_COLON                14
110 #define LEXCHAR_EOL                  15
111 #define LEXCHAR_NULL                 16
112 #define LEXCHAR_OTHER                17
113 
114 #define LEXSTATE_IDLE                 0
115 #define LEXSTATE_BACKSLASHED          1
116 #define LEXSTATE_INQUOTE              2
117 #define LEXSTATE_INQUOTE_AFTERBSLASH  3
118 #define LEXSTATE_INSTRING             4
119 #define LEXSTATE_ERROR                5
120 
121 #define LEXTOK_LPAREN                 1
122 #define LEXTOK_RPAREN                 2
123 #define LEXTOK_LBRACKET               3
124 #define LEXTOK_RBRACKET               4
125 #define LEXTOK_AND                    5
126 #define LEXTOK_OR                     6
127 #define LEXTOK_NOT                    7
128 #define LEXTOK_COMMA                  8
129 #define LEXTOK_ATSIGN                 9
130 #define LEXTOK_STRING                10
131 #define LEXTOK_RANGE                 11
132 
133 #define ERR_CD_LEX                   17
134 
135 /*------------------------------*/
136 /* Defines for enumerated lists */
137 /*------------------------------*/
138 
139 typedef enum {
140   SELECTION_MODE = 1,
141   AUTOMATIC_MODE,
142   WILD_CARD_MODE,
143   MESH_TREE_MODE,
144   TAXONOMY_MODE,
145   RANGE_MODE,
146   LOOKUP_ACCN_MODE,
147   VIEW_ACCN_MODE,
148   LOOKUP_UID_MODE,
149   VIEW_UID_MODE,
150   TRANSLATE_MODE
151 } ModeChoice;
152 
153 static ENUM_ALIST(mult_alist)
154   {"Multiple",            AUTOMATIC_MODE},
155   {"Selection",           SELECTION_MODE},
156   {"Wild Card",           WILD_CARD_MODE},
157 END_ENUM_ALIST
158 
159 static ENUM_ALIST(auto_alist)
160   {"Automatic",           TRANSLATE_MODE},
161   {"Multiple",            AUTOMATIC_MODE},
162   {"Selection",           SELECTION_MODE},
163   {"Wild Card",           WILD_CARD_MODE},
164 END_ENUM_ALIST
165 
166 static ENUM_ALIST(accn_alist)
167   {"Lookup",              LOOKUP_ACCN_MODE},
168   {"Range",               RANGE_MODE},
169   {"Selection",           SELECTION_MODE},
170   {"Wild Card",           WILD_CARD_MODE},
171   {"View",                VIEW_ACCN_MODE},
172 END_ENUM_ALIST
173 
174 static ENUM_ALIST(mesh_alist)
175   {"MeSH Tree",           MESH_TREE_MODE},
176   {"Selection",           SELECTION_MODE},
177   {"Wild Card",           WILD_CARD_MODE},
178 END_ENUM_ALIST
179 
180 static ENUM_ALIST(tax_alist)
181   {"Selection",           SELECTION_MODE},
182   {"Taxonomy",            TAXONOMY_MODE},
183   {"Wild Card",           WILD_CARD_MODE},
184 END_ENUM_ALIST
185 
186 static ENUM_ALIST(default_alist)
187   {"Range",               RANGE_MODE},
188   {"Selection",           SELECTION_MODE},
189   {"Wild Card",           WILD_CARD_MODE},
190 END_ENUM_ALIST
191 
192 static ENUM_ALIST(range_alist)
193   {"Range",               RANGE_MODE},
194   {"Selection",           SELECTION_MODE},
195 END_ENUM_ALIST
196 
197 static ENUM_ALIST(trunc_alist)
198   {"Selection",           SELECTION_MODE},
199   {"Wild Card",           WILD_CARD_MODE},
200 END_ENUM_ALIST
201 
202 static ENUM_ALIST(uid_alist)
203   {"Lookup",              LOOKUP_UID_MODE},
204   {"View",                VIEW_UID_MODE},
205 END_ENUM_ALIST
206 
207 static EnumFieldAssocPtr mode_alists [] = {
208   mult_alist,
209   auto_alist,
210   accn_alist,
211   mesh_alist,
212   tax_alist,
213   default_alist,
214   range_alist,
215   trunc_alist,
216   uid_alist,
217   NULL
218 };
219 
220 typedef enum {
221   POPUP_MULT = 0,
222   POPUP_AUTO,
223   POPUP_ACCN,
224   POPUP_MESH,
225   POPUP_TAX,
226   POPUP_DEFAULT,
227   POPUP_RANGE,
228   POPUP_TRUNC,
229   POPUP_UID
230 } ModeIndex;
231 
232 /*-----------------------*/
233 /* Structure definitions */
234 /*-----------------------*/
235 
236 typedef struct trmstatedata {
237   CharPtr                   term;
238   CharPtr                   field;
239   Int4                      count;
240   Int2                      db;
241   Int2                      fld;
242   Int2                      group;
243   Int2                      above;
244   Int2                      below;
245   Int2                      state;
246   Int4Ptr                   uids;
247   CharPtr                   key;
248   struct trmstatedata PNTR  prev;
249   struct trmstatedata PNTR  next;
250 } StateData, PNTR StateDataPtr;
251 
252 typedef struct {
253   FORM_MESSAGE_BLOCK
254   E2RetrieveDocsProc  retrieveDocsProc;
255   E2RetrieveUidProc   retrieveUidProc;
256   GrouP               stdQueryGroup;
257   GrouP               advQueryGroup;
258   ButtoN              advEvaluateButton;
259   ButtoN              advRetrieveButton;
260   Int2                advQueryState;
261   ButtoN              advResetButton;
262   TexT                advQueryText;
263   Int2                advQueryLexPos;
264   CharPtr             advQueryLexStr;
265   Int2                advQueryLexState;
266   ValNodePtr          advQueryNextToken;
267   ValNode             advQueryNextRealNode;
268   Boolean             advQueryNewGroup;
269   PopuP PNTR          fieldsPopup;
270   PopuP               modesPopup [MAX_MODES];
271   GrouP               termGroup;
272   GrouP               rangeGroup;
273   IteM                advancedQueryItem;
274   IteM                explodeItem;
275   ModeChoice          currMode;
276   Int2                currField;
277   Int2                currDb;
278   DoC                 availDoc;
279   Int2                availItem;
280   Int2                availRow;
281   Int2                availClickItem;
282   Int2                availClickRow;
283   Int4                availNumTerms;
284   Int4                availPageSize;
285   Int2                availNumPages;
286   Int2                availCurrentPage;
287   Boolean             textChanged;
288   Int2                okayToAccept;
289   TexT                termText;
290   TexT                fromText;
291   TexT                toText;
292   Boolean             isValidFrom;
293   Boolean             isValidTo;
294   Boolean             isFromTextChanged;
295   Boolean             isToTextChanged;
296   Int2                currRangeField;
297   ButtoN              acceptButton;
298   PopuP               taxLineagePopup;
299   ValNodePtr          taxStrings;
300   PopuP               databasePopup;
301   ButtoN              retrieveButton;
302   ButtoN              resetButton;
303   Boolean             wasDoubleClick;
304   DoC                 chosenDoc;
305   Int2                chosenItem;
306   Int2                chosenClickItem;
307   Int2                chosenClickRow;
308   Int2                chosenClickCol;
309   Boolean             chosenInAboveBox;
310   Boolean             chosenInBelowBox;
311   Int2                chosenNumLines;
312   RecT                trackRect;
313   PoinT               trackPt;
314   StateDataPtr        termList;
315 } FormInfo, PNTR FormInfoPtr;
316 
317 /*----------------------------*/
318 /* File-wide static variables */
319 /*----------------------------*/
320 
321 static ChoicE         s_showASNItem;
322 static Entrez2InfoPtr s_masterE2ip = NULL;
323 
324 static ParData  availParFmt = { FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0 };
325 static ColData  availColFmt [] = {
326   {0, 5, 70, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE},  /* term  */
327   {0, 5, 10, 0, NULL, 'r', FALSE, TRUE, FALSE, FALSE, FALSE},   /* count */
328   {0, 5, 10, 0, NULL, 'r', FALSE, FALSE, FALSE, FALSE, TRUE}    /* leaf  */
329 };
330 
331 static ParData  chosenParFmt = { FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0 };
332 static ColData  chosenColFmt [] = {
333   {0, 23, 70, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE}, /* term  */
334   {0, 5, 10, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE},  /* field */
335   {0, 5, 10, 0, NULL, 'r', FALSE, TRUE, FALSE, FALSE, TRUE}     /* count */
336 };
337 
338 /*---------------------*/
339 /* Function prototpyes */
340 /*---------------------*/
341 
342 static Boolean RemoveTermFromList (
343   FormInfoPtr pFormInfo,
344   StateDataPtr sdp,
345   Boolean goingDown,
346   Boolean lastDraggedDown
347 );
348 static Boolean Query_TranslateAndAddBoolTerm (
349   ForM f,
350   Int2 currDb,
351   Int2 currFld,
352   CharPtr strs,
353   Int2 state,
354   Int4 num
355 );
356 
357 static Boolean LoadAvailList (FormInfoPtr pFormInfo, CharPtr str);
358 
359 /*==================================================================*/
360 /*                                                                  */
361 /*  ShowASN () -  Returns the current setting of the s_showASN      */
362 /*               static variable.                                   */
363 /*                                                                  */
364 /*==================================================================*/
365 
366 NLM_EXTERN Boolean ShowASN (void)
367 
368 {
369   Int2  val;
370 
371   /*
372   return GetStatus (s_showASNItem);
373   */
374   val = GetValue (s_showASNItem);
375   if (val >= 11) return TRUE;
376   if (val < 2) return FALSE;
377   SetValue (s_showASNItem, val - 1);
378   if (val < 2) return FALSE;
379   return TRUE;
380 }
381 
382 static void LogOrLaunch (CharPtr path, CharPtr title)
383 
384 {
385   Char    buf [257];
386   size_t  ct;
387   FILE    *ifp;
388   FILE    *ofp;
389   Int2    val;
390 
391   val = GetValue (s_showASNItem);
392   if (val == 12) {
393     ifp = FileOpen (path, "r");
394     ofp = FileOpen ("entrez2.log", "a");
395     if (ifp != NULL && ofp != NULL) {
396       while ((ct = FileRead (buf, 1, sizeof (buf) - 1, ifp)) > 0) {
397         FileWrite (buf, 1, ct, ofp);
398       }
399       fprintf (ofp, "\n");
400     }
401     FileClose (ofp);
402     FileClose (ifp);
403   } else {
404     LaunchGeneralTextViewer (path, title);
405   }
406 }
407 
408 /*==================================================================*/
409 /*                                                                  */
410 /*  DisplayEntrezRequest () - Displays an Entrez2 request in a      */
411 /*                           pop-up window.                         */
412 /*                                                                  */
413 /*==================================================================*/
414 
415 NLM_EXTERN void DisplayEntrezRequest (Entrez2RequestPtr e2rq)
416 
417 {
418   AsnIoPtr  aip;
419   Char      path [PATH_MAX];
420 
421   if (e2rq == NULL) return;
422   TmpNam (path);
423   aip = AsnIoOpen (path, "w");
424   if (aip == NULL) return;
425   Entrez2RequestAsnWrite (e2rq, aip, NULL);
426   AsnIoClose (aip);
427   LogOrLaunch (path, "Entrez2RequestAsnWrite");
428   FileRemove (path);
429 }
430 
431 /*==================================================================*/
432 /*                                                                  */
433 /*  DisplayEntrezReply () - Displays an Entrez2 reply in a pop-up   */
434 /*                         window.                                  */
435 /*                                                                  */
436 /*==================================================================*/
437 
438 NLM_EXTERN void DisplayEntrezReply (Entrez2ReplyPtr e2ry)
439 
440 {
441   AsnIoPtr  aip;
442   Char      path [PATH_MAX];
443 
444   if (e2ry == NULL) return;
445   TmpNam (path);
446   aip = AsnIoOpen (path, "w");
447   if (aip == NULL) return;
448   Entrez2ReplyAsnWrite (e2ry, aip, NULL);
449   AsnIoClose (aip);
450   LogOrLaunch (path, "Entrez2ReplyAsnWrite");
451   FileRemove (path);
452 }
453 
454 /* text version of entrez2 query for debugging purposes */
455 
456 static Entrez2ReplyPtr EntrezTextWaitForReply (
457   CONN conn
458 )
459 
460 {
461   AsnIoConnPtr     aicp;
462   AsnIoPtr         aip;
463   Char             buffer [1025];
464   time_t           currtime, starttime;
465   Entrez2ReplyPtr  e2ry = NULL;
466   Boolean          first;
467   FILE *           fp;
468   time_t           max = 0;
469   size_t           n_read;
470   Boolean          special_read = FALSE;
471   EIO_Status       status;
472   STimeout         timeout;
473   Char             tmp [PATH_MAX];
474 
475   if (conn == NULL) return NULL;
476 
477   timeout.sec = 100;
478   timeout.usec = 0;
479 
480   starttime = GetSecs ();
481   while ((status = CONN_Wait (conn, eIO_Read, &timeout)) == eIO_Timeout && max < 300) {
482     currtime = GetSecs ();
483     max = currtime - starttime;
484   }
485   if (status == eIO_Success) {
486 #ifdef OS_UNIX
487     if (getenv ("ENTREZ2_RECORD_QUERY") != 0) {
488       special_read = TRUE;
489     }
490 #endif
491     if (special_read) {
492       TmpNam (tmp);
493 #ifdef OS_UNIX
494 printf ("TmpNam '%s'\n", tmp);
495 #endif
496       fp = FileOpen (tmp, "w");
497       if (fp != NULL) {
498 
499         first = TRUE;
500         do {
501           status = CONN_Read (conn, buffer, sizeof (buffer) -1, &n_read,
502                               first ? eIO_ReadPersist : eIO_ReadPlain);
503           buffer [n_read] = '\0';
504           if (first) {
505             if (StringStr (buffer, "Entrez2-reply") == NULL) {
506               ErrPostEx (SEV_ERROR, 0, 0, "EntrezReadReply failed on '%s'", buffer);
507               FileClose (fp);
508               /*
509               FileRemove (tmp);
510               */
511               return NULL;
512             }
513             first = FALSE;
514           }
515           fprintf (fp, "%s", buffer);
516         } while (status == eIO_Success);
517         FileClose (fp);
518 
519         aip = AsnIoOpen (tmp, "r");
520         e2ry = Entrez2ReplyAsnRead (aip, NULL);
521         AsnIoClose (aip);
522         /*
523         FileRemove (tmp);
524         */
525       }
526     } else {
527       aicp = QUERY_AsnIoConnOpen ("r", conn);
528       e2ry = Entrez2ReplyAsnRead (aicp->aip, NULL);
529       QUERY_AsnIoConnClose (aicp);
530     }
531   }
532   CONN_Close (conn);
533 
534   return e2ry;
535 }
536 
537 static Entrez2ReplyPtr EntrezSpecialSynchronousQuery (
538   Entrez2RequestPtr e2rq,
539   Boolean textmode
540 )
541 
542 {
543   AsnIoConnPtr     aicp;
544   CONN             conn;
545   Entrez2ReplyPtr  e2ry;
546   CharPtr          tempcookie = NULL;
547   CharPtr          host_machine = NULL;
548   Uint2            host_port = 0;
549   CharPtr          host_path = NULL;
550   CharPtr          env_machine = NULL;
551   CharPtr          env_path = NULL;
552   CharPtr          env_port = NULL;
553   CharPtr          env_service = NULL;
554   int              val = 0;
555 
556   if (e2rq == NULL) return NULL;
557 
558 #ifdef OS_UNIX
559   env_machine = (CharPtr) getenv ("NCBI_ENTREZ2_HOST_MACHINE");
560   if (! StringHasNoText (env_machine)) {
561     host_machine = env_machine;
562   }
563 #endif
564   if (StringHasNoText (host_machine)) {
565     host_machine = "www.ncbi.nlm.nih.gov";
566   }
567 
568 #ifdef OS_UNIX
569   env_port = (CharPtr) getenv ("NCBI_ENTREZ2_HOST_PORT");
570   if (! StringHasNoText (env_port)) {
571     if (sscanf (env_port, "%d", &val) == 1) {
572       host_port = (Uint2) val;
573     }
574   }
575 #endif
576   if (host_port == 0) {
577     host_port = 80;
578   }
579 
580 #ifdef OS_UNIX
581   env_path = (CharPtr) getenv ("NCBI_ENTREZ2_HOST_PATH");
582   if (! StringHasNoText (env_path)) {
583     host_path = env_path;
584   }
585 #endif
586   if (StringHasNoText (host_path)) {
587     host_path = "/entrez/eutils/entrez2server.fcgi";
588   }
589 
590   if (textmode) {
591     conn = QUERY_OpenUrlQuery (host_machine, host_port, host_path, NULL,
592                                "Entrez2Text", 30, eMIME_T_NcbiData,
593                                eMIME_AsnText, eENCOD_None, 0);
594 
595     aicp = QUERY_AsnIoConnOpen ("w", conn);
596   } else {
597     conn = QUERY_OpenUrlQuery (host_machine, host_port, host_path, NULL,
598                                "Entrez2Text", 30, eMIME_T_NcbiData,
599                                eMIME_AsnBinary, eENCOD_None, 0);
600 
601     aicp = QUERY_AsnIoConnOpen ("wb", conn);
602   }
603 
604   tempcookie = e2rq->cookie;
605 
606   Entrez2RequestAsnWrite (e2rq, aicp->aip, NULL);
607 
608   e2rq->cookie = tempcookie;
609 
610   AsnIoFlush (aicp->aip);
611   QUERY_AsnIoConnClose (aicp);
612 
613   QUERY_SendQuery (conn);
614 
615   if (textmode) {
616     e2ry = EntrezTextWaitForReply (conn);
617   } else {
618     e2ry = EntrezWaitForReply (conn);
619   }
620 
621   return e2ry;
622 }
623 
624 extern Entrez2ReplyPtr SpecialEntrezSynchronousQuery (
625   Entrez2RequestPtr e2rq
626 );
627 
628 extern Entrez2ReplyPtr SpecialEntrezSynchronousQuery (
629   Entrez2RequestPtr e2rq
630 )
631 
632 {
633 #ifdef OS_UNIX
634   if (getenv ("ENTREZ2_TEXT_QUERY") != 0) {
635     return EntrezSpecialSynchronousQuery (e2rq, TRUE);
636   }
637   if (getenv ("ENTREZ2_BINARY_QUERY") != 0) {
638     return EntrezSpecialSynchronousQuery (e2rq, FALSE);
639   }
640 #endif
641   return EntrezSynchronousQuery (e2rq);
642 }
643 
644 /*==================================================================*/
645 /*                                                                  */
646 /*  DBGetInfo () - Given a database ID, return the DB pointer.      */
647 /*                                                                  */
648 /*==================================================================*/
649 
650 static Entrez2DbInfoPtr DBGetInfo (Int2 dbId)
651 
652 {
653   Int2              count;
654   Entrez2InfoPtr    e2ip;
655   Entrez2DbInfoPtr  e2db;
656 
657   /*------------------*/
658   /* Check parameters */
659   /*------------------*/
660 
661   if (dbId < 0) return NULL;
662 
663   /*----------------------------------*/
664   /* Get information on the databases */
665   /*----------------------------------*/
666 
667   e2ip = Query_GetInfo ();
668 
669   /*-----------------------*/
670   /* Find the requested DB */
671   /*-----------------------*/
672 
673   for (e2db = e2ip->db_info, count = 0; e2db != NULL; e2db = e2db->next, count++) {
674     if (count == dbId) return e2db;
675   }
676 
677   return NULL;
678 }
679 
680 /*==================================================================*/
681 /*                                                                  */
682 /*  DBGetNameFromID () - Given a DB ID, returns its name.           */
683 /*                                                                  */
684 /*==================================================================*/
685 
686 NLM_EXTERN CharPtr DBGetNameFromID (Int2 dbId)
687 
688 {
689   Int2              count;
690   Entrez2InfoPtr    e2ip;
691   Entrez2DbInfoPtr  e2db;
692 
693   /*-----------------*/
694   /* Check parameter */
695   /*-----------------*/
696 
697   if (dbId < 0) return NULL;
698 
699   /*----------------------------------*/
700   /* Get information on the databases */
701   /*----------------------------------*/
702 
703   e2ip = Query_GetInfo ();
704 
705   /*--------------------------*/
706   /* Find to the requested DB */
707   /*--------------------------*/
708 
709   for (e2db = e2ip->db_info, count = 0; e2db != NULL; e2db = e2db->next, count++) {
710     if (count == dbId) return e2db->db_name;
711   }
712 
713   return NULL;
714 }
715 
716 /*==================================================================*/
717 /*                                                                  */
718 /*  DBGetIDFromName () - Given a DB name, returns its unique ID.    */
719 /*                                                                  */
720 /*==================================================================*/
721 
722 NLM_EXTERN Int2 DBGetIDFromName (CharPtr dbName)
723 
724 {
725   Int2              count;
726   Entrez2InfoPtr    e2ip;
727   Entrez2DbInfoPtr  e2db;
728 
729   /*-----------------*/
730   /* Check parameter */
731   /*-----------------*/
732 
733   if (dbName == NULL) return -1;
734 
735   /*----------------------------------*/
736   /* Get information on the databases */
737   /*----------------------------------*/
738 
739   e2ip = Query_GetInfo ();
740 
741   /*---------------------------*/
742   /* Look for the requested DB */
743   /*---------------------------*/
744 
745   for (e2db = e2ip->db_info, count = 0; e2db != NULL; e2db = e2db->next, count++) {
746     if (StrICmp (e2db->db_name, dbName) == 0) return count;
747   }
748 
749   return -1;
750 }
751 
752 /*==================================================================*/
753 /*                                                                  */
754 /*  FieldGetInfo () - Given a database ID and a field ID, return    */
755 /*                    the field name.                               */
756 /*                                                                  */
757 /*==================================================================*/
758 
759 static Entrez2FieldInfoPtr FieldGetInfo (Int2 dbId, Int2 fieldId)
760 
761 {
762   Int2                 count;
763   Entrez2DbInfoPtr     e2db;
764   Entrez2FieldInfoPtr  e2fd;
765 
766   /*------------------*/
767   /* Check parameters */
768   /*------------------*/
769 
770   if (dbId < 0 || fieldId < 0) return NULL;
771 
772   /*----------------------------------*/
773   /* Find the requested DB            */
774   /*----------------------------------*/
775 
776   e2db = DBGetInfo (dbId);
777   if (e2db == NULL) return NULL;
778 
779   /*----------------*/
780   /* Get field info */
781   /*----------------*/
782 
783   for (e2fd = e2db->fields, count = 0; e2fd != NULL; e2fd = e2fd->next, count++) {
784     if (count == fieldId) return e2fd;
785   }
786 
787   return NULL;
788 }
789 
790 /*==================================================================*/
791 /*                                                                  */
792 /*  IsValidFieldName () - Given a database ID and a field name,     */
793 /*                        check to see if it is as valid name.      */
794 /*                                                                  */
795 /*==================================================================*/
796 
797 static Boolean IsValidFieldName (Int2 dbId, CharPtr fieldName)
798 
799 {
800   Entrez2DbInfoPtr     e2db;
801   Entrez2FieldInfoPtr  e2fd;
802 
803   /*------------------*/
804   /* Check parameters */
805   /*------------------*/
806 
807   if (dbId < 0 || fieldName == NULL) return FALSE;
808 
809   /*-----------------------*/
810   /* Find the requested DB */
811   /*-----------------------*/
812 
813   e2db = DBGetInfo (dbId);
814   if (e2db == NULL) return FALSE;
815 
816   /*----------------*/
817   /* Get field info */
818   /*----------------*/
819 
820   for (e2fd = e2db->fields; e2fd != NULL; e2fd = e2fd->next) {
821     if (StrICmp (e2fd->field_name, fieldName) == 0)
822       return TRUE;
823   }
824 
825   return FALSE;
826 }
827 
828 /*===================================================================*/
829 /*                                                                   */
830 /*  FieldGetNameFromMenuName () - Given a field menu name and a      */
831 /*                               database ID, return the field name. */
832 /*                                                                   */
833 /*===================================================================*/
834 
835 static CharPtr FieldGetNameFromMenuName (Int2 dbId, CharPtr menuName)
836 
837 {
838   Entrez2DbInfoPtr     e2db;
839   Entrez2FieldInfoPtr  e2fd;
840 
841   /*------------------*/
842   /* Check parameters */
843   /*------------------*/
844 
845   if (menuName == NULL || dbId < 0) return NULL;
846 
847   /*-----------------------*/
848   /* Find the requested DB */
849   /*-----------------------*/
850 
851   e2db = DBGetInfo (dbId);
852   if (e2db == NULL) return NULL;
853 
854   /*--------------------------*/
855   /* Find the requested field */
856   /*--------------------------*/
857 
858   for (e2fd = e2db->fields; e2fd != NULL; e2fd = e2fd->next) {
859     if (StrICmp (e2fd->field_menu, menuName) == 0) return e2fd->field_name;
860   }
861 
862   return NULL;
863 }
864 
865 /*==================================================================*/
866 /*                                                                  */
867 /*  FieldGetIDFromName () - Given a field name and a database ID,   */
868 /*                         return the field ID.                     */
869 /*                                                                  */
870 /*==================================================================*/
871 
872 static Int2 FieldGetIDFromName (Int2 dbId, CharPtr fieldName)
873 
874 {
875   Int2                 count;
876   Entrez2DbInfoPtr     e2db;
877   Entrez2FieldInfoPtr  e2fd;
878 
879   /*------------------*/
880   /* Check parameters */
881   /*------------------*/
882 
883   if (fieldName == NULL || dbId < 0) return -1;
884 
885   /*-----------------------*/
886   /* Find the requested DB */
887   /*-----------------------*/
888 
889   e2db = DBGetInfo (dbId);
890   if (e2db == NULL) return -1;
891 
892   /*--------------------------*/
893   /* Find the requested field */
894   /*--------------------------*/
895 
896   for (e2fd = e2db->fields, count = 0; e2fd != NULL; e2fd = e2fd->next, count++) {
897     if (StrICmp (e2fd->field_name, fieldName) == 0) return count;
898   }
899 
900   return -1;
901 }
902 
903 /*==================================================================*/
904 /*                                                                  */
905 /*  FieldGetInfoFromName () - This is desigend to get field info    */
906 /*                           given only a field name. It is useful  */
907 /*                           for a getting information on a field   */
908 /*                           in a sorted alist of fields.           */
909 /*                                                                  */
910 /*==================================================================*/
911 
912 static Entrez2FieldInfoPtr FieldGetInfoFromName (CharPtr fieldName)
913 
914 {
915   Int2                 count;
916   Entrez2InfoPtr       e2ip;
917   Entrez2DbInfoPtr     e2db;
918   Entrez2FieldInfoPtr  e2fd;
919 
920   /*------------------*/
921   /* Check parameters */
922   /*------------------*/
923 
924   if (fieldName == NULL) return NULL;
925 
926   /*----------------------------------*/
927   /* Get information on the databases */
928   /*----------------------------------*/
929 
930   e2ip = Query_GetInfo ();
931 
932   /*-------------------------------*/
933   /* Find the requested field info */
934   /*-------------------------------*/
935 
936   for (e2db = e2ip->db_info, count = 0; e2db != NULL; e2db = e2db->next, count++) {
937     for (e2fd = e2db->fields; e2fd != NULL; e2fd = e2fd->next) {
938       if (StrICmp (e2fd->field_name, fieldName) == 0) return e2fd;
939     }
940   }
941 
942   return NULL;
943 }
944 
945 /*==================================================================*/
946 /*                                                                  */
947 /* FieldGetModePopup () -                                           */
948 /*                                                                  */
949 /*==================================================================*/
950 
951 static Int2 FieldGetModePopup (Int2 dbId, Int2 fieldId, EnumFieldAssocPtr fieldAList, FormInfoPtr pFormInfo)
952 
953 {
954   Entrez2DbInfoPtr     dbInfo;
955   Entrez2FieldInfoPtr  fieldInfo;
956   Boolean              is_rangable;
957   Boolean              is_truncatable;
958   ModeIndex            modeId = POPUP_DEFAULT;
959 
960   /*-----------------------------------------*/
961   /* Find the requested field, and determine */
962   /* its corresponding mode list popup.      */
963   /*-----------------------------------------*/
964 
965   dbInfo = DBGetInfo (dbId);
966   if (dbInfo == NULL) return -1;
967 
968   fieldInfo = FieldGetInfo (dbId, fieldId);
969   if (fieldInfo == NULL) return -1;
970 
971   /* is_rangable = fieldInfo->is_rangable; */
972   is_rangable = (Boolean) (fieldInfo->is_date || fieldInfo->is_numerical);
973   /* is_truncatable = fieldInfo->is_truncatable; */
974   is_truncatable = (Boolean) (! is_rangable);
975 
976   if (StringICmp (dbInfo->db_name, "PubMed") == 0 &&
977       StringICmp (fieldInfo->field_name, "ALL") == 0) {
978     modeId = POPUP_AUTO;
979   } else if (StringICmp (fieldInfo->field_name, "ALL") == 0) {
980     modeId = POPUP_MULT;
981   } else if ((StringICmp (fieldInfo->field_name, "TITL") == 0) ||
982              (StringICmp (fieldInfo->field_name, "WORD") == 0) ||
983              (StringICmp (fieldInfo->field_name, "TIAB") == 0)) {
984     modeId = POPUP_MULT;
985   } else if (StringICmp (fieldInfo->field_name, "ACCN") == 0 ||
986              StringICmp (fieldInfo->field_name, "PACC") == 0) {
987     modeId = POPUP_ACCN;
988   } else if (StringICmp (fieldInfo->field_name, "ORGN") == 0) {
989     modeId = POPUP_TAX;
990   } else if (StringICmp (fieldInfo->field_name, "MESH") == 0 ||
991              StringICmp (fieldInfo->field_name, "MAJR") == 0) {
992     modeId = POPUP_MESH;
993   } else if (StringICmp (fieldInfo->field_name, "UID") == 0) {
994     modeId = POPUP_UID;
995   } else if (is_rangable && is_truncatable) {
996     modeId = POPUP_DEFAULT;
997   } else if (is_rangable) {
998     modeId = POPUP_RANGE;
999   } else if (is_truncatable) {
1000     modeId = POPUP_TRUNC;
1001   } else {
1002     modeId = POPUP_DEFAULT;
1003   }
1004 
1005   pFormInfo->currField = FieldGetIDFromName (dbId, fieldInfo->field_name);
1006   return modeId;
1007 }
1008 
1009 /*==================================================================*/
1010 /*                                                                  */
1011 /*  CreateDatabaseAlist () - Returns alist of database names        */
1012 /*                                                                  */
1013 /*==================================================================*/
1014 
1015 EnumFieldAssocPtr CreateDatabaseAlist (Entrez2InfoPtr e2ip)
1016 
1017 {
1018   EnumFieldAssocPtr  alist;
1019   Uint1              choice;
1020   Entrez2DbInfoPtr   e2db;
1021   ValNodePtr         head = NULL;
1022 
1023   if (e2ip == NULL || e2ip->db_count < 1) return NULL;
1024 
1025   for (e2db = e2ip->db_info; e2db != NULL; e2db = e2db->next) {
1026     choice = (Uint1) DBGetIDFromName (e2db->db_name);
1027     ValNodeCopyStr (&head, choice, e2db->db_menu);
1028   }
1029 
1030   alist = MakeEnumFieldAlistFromValNodeList (head);
1031   ValNodeFreeData (head);
1032 
1033   return alist;
1034 }
1035 
1036 /*==================================================================*/
1037 /*                                                                  */
1038 /*  CreateFieldAlist () - Returns sorted alist of field names for   */
1039 /*                       the given database.                        */
1040 /*                                                                  */
1041 /*==================================================================*/
1042 
1043 EnumFieldAssocPtr CreateFieldAlist (Entrez2DbInfoPtr e2db)
1044 
1045 {
1046   EnumFieldAssocPtr    alist;
1047   Uint1                choice;
1048   Entrez2FieldInfoPtr  fieldInfo;
1049   Int2                 dbId;
1050   ValNodePtr           head = NULL;
1051 
1052   if (e2db == NULL || e2db->field_count < 1) return NULL;
1053 
1054   dbId = DBGetIDFromName (e2db->db_name);
1055   for (fieldInfo = e2db->fields; fieldInfo != NULL; fieldInfo = fieldInfo->next) {
1056     choice = (Uint1) FieldGetIDFromName (dbId, fieldInfo->field_name);
1057     ValNodeCopyStr (&head, choice, fieldInfo->field_menu);
1058   }
1059 
1060   head = ValNodeSort (head, SortVnpByString);
1061 
1062   alist = MakeEnumFieldAlistFromValNodeList (head);
1063   ValNodeFreeData (head);
1064 
1065   return alist;
1066 }
1067 
1068 /*==================================================================*/
1069 /*                                                                  */
1070 /*  CreateAllFieldsAlist () - Returns sorted uniqued alist of all   */
1071 /*                           field names.                           */
1072 /*                                                                  */
1073 /*==================================================================*/
1074 
1075 static EnumFieldAssocPtr CreateAllFieldsAlist (Entrez2InfoPtr e2ip)
1076 
1077 {
1078   EnumFieldAssocPtr    alist;
1079   Uint1                choice;
1080   Entrez2DbInfoPtr     e2db;
1081   Entrez2FieldInfoPtr  fieldInfo;
1082   Int2                 dbId;
1083   ValNodePtr           head = NULL;
1084 
1085   for (e2db = e2ip->db_info; e2db != NULL; e2db = e2db->next) {
1086     dbId = DBGetIDFromName (e2db->db_name);
1087     for (fieldInfo = e2db->fields; fieldInfo != NULL; fieldInfo = fieldInfo->next) {
1088       choice = (Uint1) FieldGetIDFromName (dbId, fieldInfo->field_name);
1089       ValNodeCopyStr (&head, choice, fieldInfo->field_name);
1090     }
1091   }
1092 
1093   head = ValNodeSort (head, SortVnpByString);
1094   head = UniqueValNode (head);
1095 
1096   alist = MakeEnumFieldAlistFromValNodeList (head);
1097   ValNodeFreeData (head);
1098 
1099   return alist;
1100 }
1101 
1102 /*==================================================================*/
1103 /*                                                                  */
1104 /*  GetUidFromAccn () -                                             */
1105 /*                                                                  */
1106 /*==================================================================*/
1107 
1108 static Uint4 GetUidFromAccn (CharPtr dbName, CharPtr accn)
1109 
1110 {
1111   Entrez2BooleanReplyPtr  e2br;
1112   Entrez2IdListPtr        e2id;
1113   Entrez2RequestPtr       e2rq;
1114   Entrez2ReplyPtr         e2ry;
1115   Char                    ch;
1116   CharPtr                 ptr;
1117   Char                    str [61];
1118   Uint4                   uid = 0;
1119 
1120   if (StringHasNoText (dbName) || StringHasNoText (accn)) return 0;
1121 
1122   StringNCpy_0 (str, accn, sizeof (str));
1123   ptr = str;
1124   ch = *ptr;
1125   while (ch != '\0') {
1126     if (ch == '|' || ch == '.') {
1127       *ptr = ' ';
1128     }
1129     ptr++;
1130     ch = *ptr;
1131   }
1132   TrimSpacesAroundString (str);
1133   if (StringStr (str, "[ACCN]") == NULL) {
1134     StringCat (str, "[ACCN]");
1135   }
1136   e2rq = EntrezCreateBooleanRequest (TRUE, FALSE, dbName, str, 0, 0, NULL, 1, 0);
1137 
1138   if (e2rq == NULL) return 0;
1139   e2ry = SpecialEntrezSynchronousQuery (e2rq);
1140   e2rq = Entrez2RequestFree (e2rq);
1141   if (e2ry == NULL) return 0;
1142   e2br = EntrezExtractBooleanReply (e2ry);
1143   if (e2br == NULL) return 0;
1144 
1145   if (e2br->count > 0) {
1146     e2id = e2br->uids;
1147     if (e2id != NULL && e2id->num > 0 && e2id->uids != NULL) {
1148       BSSeek (e2id->uids, 0, SEEK_SET);
1149       uid = Nlm_BSGetUint4 (e2id->uids);
1150     }
1151   }
1152 
1153   Entrez2BooleanReplyFree (e2br);
1154 
1155   return uid;
1156 }
1157 
1158 /*==================================================================*/
1159 /*                                                                  */
1160 /*  ProcessDirectLookup () -                                        */
1161 /*                                                                  */
1162 /*==================================================================*/
1163 
1164 static void ProcessDirectLookup (FormInfoPtr pFormInfo, CharPtr str)
1165 
1166 {
1167   CharPtr  dbName;
1168   Int4     uid;
1169 
1170   uid = 0;
1171 
1172   /*----------------------------------------*/
1173   /* Convert the given string to a UID and */
1174   /* check to see if it is a valid one.    */
1175   /*---------------------------------------*/
1176 
1177   if ((pFormInfo->currMode == LOOKUP_ACCN_MODE) || (pFormInfo->currMode == VIEW_ACCN_MODE)) {
1178     if (StringLen (str) > 0) {
1179       dbName = DBGetNameFromID (pFormInfo->currDb);
1180       uid = GetUidFromAccn (dbName, str);
1181     }
1182   } else if ((pFormInfo->currMode == LOOKUP_UID_MODE) || (pFormInfo->currMode == VIEW_UID_MODE)) {
1183     if (! StrToLong (str, &uid)) {
1184       Message (MSG_OK, "You must enter an integer");
1185       return;
1186     }
1187   } else
1188     return;
1189 
1190   if (uid <= 0) {
1191     if (pFormInfo->currMode == LOOKUP_ACCN_MODE || pFormInfo->currMode == VIEW_ACCN_MODE) {
1192       Message (MSG_OK, "This accession is not present in the database");
1193     } else {
1194       Message (MSG_OK, "This UID is not present in the database");
1195     }
1196     return;
1197   }
1198 
1199   /*-------------------------------------*/
1200   /* Lookup the record for the given UID */
1201   /* and display it in a DocSum window.  */
1202   /*-------------------------------------*/
1203 
1204   if (pFormInfo->currMode == LOOKUP_ACCN_MODE || pFormInfo->currMode == LOOKUP_UID_MODE) {
1205     dbName = DBGetNameFromID (pFormInfo->currDb);
1206     pFormInfo->retrieveUidProc (pFormInfo->form, uid, dbName);
1207   } else {
1208     LaunchRecViewer (pFormInfo->form, uid, 1, &uid, pFormInfo->currDb, 1);
1209   }
1210 }
1211 
1212 /*==================================================================*/
1213 /*                                                                  */
1214 /*  DoResetAvail () - Clears out the Term List object.              */
1215 /*                                                                  */
1216 /*==================================================================*/
1217 
1218 static void DoResetAvail (FormInfoPtr pFormInfo, Boolean clearTerm)
1219 
1220 {
1221   Int2  i;
1222 
1223   if (clearTerm) {
1224     SafeSetTitle (pFormInfo->termText, "");
1225     SafeSetTitle (pFormInfo->toText, "");
1226     SafeSetTitle (pFormInfo->fromText, "");
1227     SafeDisable (pFormInfo->acceptButton);
1228   } else if (pFormInfo->currMode == RANGE_MODE) {
1229     if (TextHasNoText (pFormInfo->fromText) && TextHasNoText (pFormInfo->toText))
1230       SafeDisable (pFormInfo->acceptButton);
1231     else
1232       SafeEnable (pFormInfo->acceptButton);
1233   } else {
1234     if (TextHasNoText (pFormInfo->termText))
1235       SafeDisable (pFormInfo->acceptButton);
1236     else
1237       SafeEnable (pFormInfo->acceptButton);
1238   }
1239 
1240   pFormInfo->availItem = 0;
1241   pFormInfo->availRow = 0;
1242   Reset (pFormInfo->availDoc);
1243   SetDocCache (pFormInfo->availDoc, NULL, NULL, NULL);
1244 
1245   for (i = 0; i < 7; i++)
1246     AppendText (pFormInfo->availDoc, " \n", &availParFmt, availColFmt, systemFont);
1247 
1248   InvalDocument (pFormInfo->availDoc);
1249   SafeHide (pFormInfo->taxLineagePopup);
1250   Reset (pFormInfo->taxLineagePopup);
1251   pFormInfo->taxStrings = ValNodeFreeData (pFormInfo->taxStrings);
1252   pFormInfo->availNumTerms = 0;
1253   pFormInfo->availPageSize = 0;
1254   pFormInfo->availNumPages = 0;
1255 }
1256 
1257 /*==================================================================*/
1258 /*                                                                  */
1259 /* FreeTerm () - Frees a given term from the term list.             */
1260 /*                                                                  */
1261 /*==================================================================*/
1262 
1263 static void FreeTerm (StateDataPtr termPtr)
1264 
1265 {
1266   MemFree (termPtr->term);
1267   MemFree (termPtr->field);
1268   MemFree (termPtr);
1269 }
1270 
1271 /*==================================================================*/
1272 /*                                                                  */
1273 /* FreeTermList () - Frees all the terms in the current query       */
1274 /*                    term list.                                    */
1275 /*                                                                  */
1276 /*==================================================================*/
1277 
1278 static StateDataPtr FreeTermList (FormInfoPtr pFormInfo)
1279 
1280 {
1281   StateDataPtr  next;
1282 
1283   while (pFormInfo->termList != NULL) {
1284     next = pFormInfo->termList->next;
1285     FreeTerm (pFormInfo->termList);
1286     pFormInfo->termList = next;
1287   }
1288 
1289   return NULL;
1290 }
1291 
1292 /*==================================================================*/
1293 /*                                                                  */
1294 /*  ResetChosen () - Clears out the Query Refinement object.        */
1295 /*                                                                  */
1296 /*==================================================================*/
1297 
1298 static void ResetChosen (FormInfoPtr pFormInfo)
1299 
1300 {
1301   /*--------------*/
1302   /* Clear it out */
1303   /*--------------*/
1304 
1305   Reset (pFormInfo->chosenDoc);
1306   FreeTermList (pFormInfo);
1307   SetDocCache (pFormInfo->chosenDoc, NULL, NULL, NULL);
1308 
1309   InvalDocument (pFormInfo->chosenDoc);
1310   pFormInfo->chosenNumLines = 0;
1311 
1312   SafeSetTitle (pFormInfo->retrieveButton, "Retrieve 0 Documents");
1313   SafeDisable (pFormInfo->retrieveButton);
1314 }
1315 
1316 /*==================================================================*/
1317 /*                                                                  */
1318 /*  Reset_Callback () - Called when reset button is pushed. Clears  */
1319 /*                     the Term List and Query Refinement windows.  */
1320 /*                                                                  */
1321 /*==================================================================*/
1322 
1323 static void Reset_Callback (ButtoN b)
1324 
1325 {
1326   FormInfoPtr  pFormInfo;
1327 
1328   pFormInfo = (FormInfoPtr) GetObjectExtra (b);
1329   DoResetAvail (pFormInfo, TRUE);
1330   ResetChosen (pFormInfo);
1331   Reset (pFormInfo->advQueryText);
1332   pFormInfo->isValidFrom = FALSE;
1333   pFormInfo->isValidTo = FALSE;
1334 }
1335 
1336 /*==================================================================*/
1337 /*                                                                  */
1338 /*  StateDataNew() - Creates a new Query term structure and adds    */
1339 /*                     it to the query term list.                   */
1340 /*                                                                  */
1341 /*==================================================================*/
1342 
1343 static StateDataPtr StateDataNew (FormInfoPtr pFormInfo)
1344 
1345 {
1346   StateDataPtr  newNode;
1347   StateDataPtr  tempNode;
1348 
1349   /*-------------------*/
1350   /* Create a new node */
1351   /*-------------------*/
1352 
1353   newNode = (StateDataPtr) MemNew (sizeof (StateData));
1354   if (newNode == NULL) return NULL;
1355 
1356   /*-------------------------------*/
1357   /* Add it to the end of the list */
1358   /*-------------------------------*/
1359 
1360   tempNode = pFormInfo->termList;
1361   if (tempNode != NULL) {
1362     while (tempNode->next != NULL)
1363       tempNode = tempNode->next;
1364     tempNode->next = newNode;
1365     newNode->prev = tempNode;
1366   } else {                      /* Empty list -- this is first term */
1367 
1368     newNode->prev = NULL;
1369     newNode->next = NULL;
1370     pFormInfo->termList = newNode;
1371   }
1372 
1373   /*---------------------*/
1374   /* Return successfully */
1375   /*---------------------*/
1376 
1377   return newNode;
1378 }
1379 
1380 /*===================================================================*/
1381 /*                                                                   */
1382 /*  CreateTerm () - Creates a new boolean term using the given       */
1383 /*                       data and adds it to the linked list of      */
1384 /*                       terms.                                      */
1385 /*                                                                   */
1386 /*===================================================================*/
1387 
1388 static StateDataPtr CreateTerm (
1389   ForM    f,
1390   Int2    currDb,
1391   Int2    currFld,
1392   CharPtr strs,
1393   Int2    state,
1394   Int4    num,
1395   Boolean allowDuplicates
1396 )
1397 
1398 {
1399   StateDataPtr         prev;
1400   StateDataPtr         sdp;
1401   Entrez2FieldInfoPtr  fieldInfo;
1402   FormInfoPtr          pFormInfo;
1403 
1404   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
1405 
1406   /*----------------------------------*/
1407   /* Make sure we're don't try to add */
1408   /* the same string twice.           */
1409   /*----------------------------------*/
1410 
1411   if (! allowDuplicates) {
1412     for (sdp = pFormInfo->termList; sdp != NULL; sdp = sdp->next) {
1413       if (MeshStringICmp (sdp->term, strs) == 0 &&
1414           sdp->db == currDb && sdp->fld == currFld) return NULL;
1415     }
1416   }
1417 
1418   /*------------------------------*/
1419   /* Create a term for the string */
1420   /* on the end of the list.      */
1421   /*------------------------------*/
1422 
1423   sdp = StateDataNew (pFormInfo);
1424   if (pFormInfo->termList == NULL)
1425     pFormInfo->termList = sdp;
1426 
1427   if (sdp == NULL) return NULL;
1428 
1429   (pFormInfo->chosenNumLines)++;
1430 
1431   sdp->term = StringSave (strs);
1432   sdp->count = num;
1433   sdp->db = currDb;
1434   sdp->fld = currFld;
1435   sdp->uids = NULL;
1436   sdp->key = NULL;
1437   fieldInfo = FieldGetInfo (currDb, currFld);
1438   if (fieldInfo == NULL) return NULL;
1439   sdp->field = StringSave (fieldInfo->field_name);
1440   if (sdp->field == NULL)
1441     sdp->field = StringSave ("----");
1442   sdp->group = GROUP_SINGLE;
1443   sdp->above = ENTREZ_OP_NONE;
1444 
1445   /*-------------------------------------*/
1446   /* Add the term to the current Query's */
1447   /* linked list of terms.               */
1448   /*-------------------------------------*/
1449 
1450   prev = sdp->prev;
1451   if (prev != NULL) {
1452     sdp->above = ENTREZ_OP_AND;
1453     prev->below = ENTREZ_OP_AND;
1454   }
1455   sdp->below = ENTREZ_OP_NONE;
1456   sdp->state = state;
1457 
1458   /*------------------------------*/
1459   /* Return a ptr to the new term */
1460   /*------------------------------*/
1461 
1462   return sdp;
1463 }
1464 
1465 /*==================================================================*/
1466 /*                                                                  */
1467 /*  DisplayTerm () -                                                */
1468 /*                                                                  */
1469 /*==================================================================*/
1470 
1471 static void DisplayTerm (FormInfoPtr pFormInfo, CharPtr term, CharPtr fieldName, Int4 total)
1472 
1473 {
1474   RecT  r;
1475   BaR   sb;
1476   Char  strn [256];
1477 
1478   /*------------------------------------------*/
1479   /* Create a display string for the term and */
1480   /* add it to the 'chosen' window.           */
1481   /*------------------------------------------*/
1482 
1483   sprintf (strn, "%s\t [%s]\t%ld\n", term, fieldName, (long) total);
1484   AppendText (pFormInfo->chosenDoc, strn, &chosenParFmt, chosenColFmt, systemFont);
1485 
1486   /*---------------------------------*/
1487   /* Display our new query string in */
1488   /* Query Refinement window.        */
1489   /*---------------------------------*/
1490 
1491   InvalDocRows (pFormInfo->chosenDoc, pFormInfo->chosenNumLines, 1, 1);
1492   AdjustDocScroll (pFormInfo->chosenDoc);
1493   sb = GetSlateVScrollBar ((SlatE) pFormInfo->chosenDoc);
1494   ResetClip ();
1495   SetBarValue (sb, MAX (pFormInfo->chosenNumLines - 7, 0));
1496   ObjectRect (pFormInfo->chosenDoc, &r);
1497   InsetRect (&r, 4, 4);
1498   r.right = r.left + 16;
1499   InsetRect (&r, -1, -1);
1500   Select (pFormInfo->chosenDoc);
1501   InvalRect (&r);
1502 
1503   Update ();
1504 }
1505 
1506 /*==================================================================*/
1507 /*                                                                  */
1508 /*  Query_AddBoolTerm () - Adds a boolean term to the linked list   */
1509 /*                        of terms that form the query.             */
1510 /*                                                                  */
1511 /*==================================================================*/
1512 
1513 static StateDataPtr Query_AddBoolTerm (ForM f, Int2 currDb, Int2 currFld, CharPtr strs, Int2 state, Int4 num)
1514 
1515 {
1516   StateDataPtr  sdp;
1517   FormInfoPtr   pFormInfo;
1518 
1519   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
1520 
1521   /*-----------------------------*/
1522   /* Add the term and display it */
1523   /*-----------------------------*/
1524 
1525   sdp = CreateTerm (f, currDb, currFld, strs, state, num, FALSE);
1526   if (sdp != NULL) {
1527     DisplayTerm (pFormInfo, strs, sdp->field, num);
1528   }
1529 
1530   /*------------------------------*/
1531   /* Return a ptr to the new term */
1532   /*------------------------------*/
1533 
1534   return sdp;
1535 }
1536 
1537 /*==================================================================*/
1538 /*                                                                  */
1539 /*  ProcessMeshTerm () -                                            */
1540 /*                                                                  */
1541 /*==================================================================*/
1542 
1543 static void ProcessMeshTerm (FormInfoPtr pFormInfo, CharPtr str)
1544 
1545 {
1546   Int4     iTermCount;
1547   CharPtr  ptr;
1548   CharPtr  text;
1549 
1550   /*---------------------------*/
1551   /* Trim off extra spaces and */
1552   /* curly-bracketed info      */
1553   /*---------------------------*/
1554 
1555   ptr = str;
1556   while (*ptr != '\0' && *ptr != '{') {
1557     ptr++;
1558   }
1559   *ptr = '\0';
1560 
1561   /*-----------------------------*/
1562   /* Get the term count from the */
1563   /* term selection window.      */
1564   /*-----------------------------*/
1565 
1566   text = GetDocText (pFormInfo->availDoc, pFormInfo->availItem, pFormInfo->availRow, E2_COUNT_COL);
1567   TrimSpacesAroundString (text);
1568   StrToLong (text, &iTermCount);
1569   MemFree (text);
1570 
1571   /*-------------------------------*/
1572   /* Load the chosen term into the */
1573   /* query refinement window.      */
1574   /*-------------------------------*/
1575 
1576   Query_AddBoolTerm (pFormInfo->form, pFormInfo->currDb, pFormInfo->currField, str, STATE_ON, iTermCount);
1577 }
1578 
1579 /*==================================================================*/
1580 /*                                                                  */
1581 /*  ValNodeMerge () -                                               */
1582 /*                                                                  */
1583 /*==================================================================*/
1584 
1585 static CharPtr ValNodeMerge (ValNodePtr head)
1586 
1587 {
1588   size_t      len;
1589   CharPtr     str;
1590   CharPtr     to;
1591   ValNodePtr  vnp;
1592 
1593   if (head == NULL) return NULL;
1594 
1595   for (vnp = head, len = 0; vnp != NULL; vnp = vnp->next)
1596     len += StringLen ((CharPtr) vnp->data.ptrvalue);
1597 
1598   str = (CharPtr) MemNew (len + 4);
1599   if (str == NULL) return NULL;
1600 
1601   for (vnp = head, to = str; vnp != NULL; vnp = vnp->next)
1602     to = StringMove (to, (CharPtr) vnp->data.ptrvalue);
1603 
1604   return str;
1605 }
1606 
1607 /*==================================================================*/
1608 /*                                                                  */
1609 /*  FetchFromTermList () -                                          */
1610 /*                                                                  */
1611 /*==================================================================*/
1612 
1613 static CharPtr FetchFromTermList (DoC d, Int2 item, Pointer ptr)
1614 
1615 {
1616   FormInfoPtr          pFormInfo;
1617   CharPtr              db, field;
1618   Entrez2RequestPtr    e2rq;
1619   Entrez2ReplyPtr      e2ry;
1620   Entrez2TermListPtr   e2tl;
1621   Entrez2TermPtr       e2tp;
1622   Entrez2FieldInfoPtr  fieldInfo;
1623   Int4                 firstPos, numTerms, page;
1624   ValNodePtr           head = NULL;
1625   CharPtr              rsult = NULL;
1626   Char                 str [256], tmp [16];
1627 
1628   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
1629 
1630   if (item < 1) return NULL;
1631 
1632   page = item - 1;
1633 
1634   db = DBGetNameFromID (pFormInfo->currDb);
1635   fieldInfo = FieldGetInfo (pFormInfo->currDb, pFormInfo->currField);
1636   field = fieldInfo->field_name;
1637   if (StringHasNoText (db) || StringHasNoText (field)) return NULL;
1638 
1639   firstPos = pFormInfo->availPageSize * page;
1640   numTerms = pFormInfo->availPageSize;
1641   if (firstPos + numTerms > pFormInfo->availNumTerms)
1642     numTerms = pFormInfo->availNumTerms - firstPos;
1643 
1644   e2rq = EntrezCreateGetTermListRequest (db, field, firstPos, numTerms);
1645   if (e2rq == NULL) return NULL;
1646 
1647   if (ShowASN () == TRUE)
1648     DisplayEntrezRequest (e2rq);
1649 
1650   e2ry = SpecialEntrezSynchronousQuery (e2rq);
1651   if (e2ry != NULL) {
1652     if (ShowASN () == TRUE)
1653       DisplayEntrezReply (e2ry);
1654 
1655     e2tl = EntrezExtractTermListReply (e2ry);
1656     if (e2tl != NULL)
1657       for (e2tp = e2tl->list; e2tp != NULL; e2tp = e2tp->next) {
1658         StringNCpy_0 (str, e2tp->term, sizeof (str) - 16);
1659         sprintf (tmp, "\t%ld\n", (long) e2tp->count);
1660         StringCat (str, tmp);
1661         ValNodeCopyStr (&head, 0, str);
1662       }
1663   }
1664   Entrez2RequestFree (e2rq);
1665 
1666   rsult = ValNodeMerge (head);
1667   ValNodeFreeData (head);
1668 
1669   return rsult;
1670 }
1671 
1672 /*==================================================================*/
1673 /*                                                                  */
1674 /*  GetTermPage () -                                                */
1675 /*                                                                  */
1676 /*==================================================================*/
1677 
1678 static Int4 GetTermPage (FormInfoPtr pFormInfo, CharPtr str)
1679 
1680 {
1681   CharPtr              db;
1682   CharPtr              field;
1683   Entrez2RequestPtr    e2rq;
1684   Entrez2ReplyPtr      e2ry;
1685   Int4                 pagesize = -1;
1686   Int4                 pos = -1;
1687   Int4                 rsult = -1;
1688   Entrez2FieldInfoPtr  fieldInfo;
1689 
1690   db = DBGetNameFromID (pFormInfo->currDb);
1691   fieldInfo = FieldGetInfo (pFormInfo->currDb, pFormInfo->currField);
1692   field = fieldInfo->field_name;
1693 
1694   if (StringHasNoText (db) || StringHasNoText (field)) return rsult;
1695 
1696   e2rq = EntrezCreateGetTermPositionRequest (db, field, str);
1697   if (e2rq == NULL) return rsult;
1698 
1699   if (ShowASN () == TRUE)
1700     DisplayEntrezRequest (e2rq);
1701 
1702   e2ry = SpecialEntrezSynchronousQuery (e2rq);
1703   if (e2ry != NULL) {
1704     if (ShowASN () == TRUE)
1705       DisplayEntrezReply (e2ry);
1706 
1707     pos = EntrezExtractTermPosReply (e2ry);
1708     pagesize = pFormInfo->availPageSize;
1709     if (pagesize > 0)
1710       rsult = (pos - 1) / pagesize;
1711   }
1712   Entrez2RequestFree (e2rq);
1713 
1714   if (pos == -1) return -1;
1715 
1716   return rsult;
1717 }
1718 
1719 /*==================================================================*/
1720 /*                                                                  */
1721 /*  ChangeUnderscoreToSpace () -                                    */
1722 /*                                                                  */
1723 /*==================================================================*/
1724 
1725 static void ChangeUnderscoreToSpace (CharPtr str)
1726 
1727 {
1728   Char     ch;
1729   CharPtr  ptr;
1730 
1731   if (str == NULL) return;
1732   ptr = str;
1733   ch = *ptr;
1734   while (ch != '\0') {
1735     if (ch == '_')
1736       *ptr = ' ';
1737     ptr++;
1738     ch = *ptr;
1739   }
1740 }
1741 
1742 /*==================================================================*/
1743 /*                                                                  */
1744 /*  ChangePeriodToSpace () -                                    */
1745 /*                                                                  */
1746 /*==================================================================*/
1747 
1748 static void ChangePeriodToSpace (CharPtr str)
1749 
1750 {
1751   Char     ch;
1752   CharPtr  ptr;
1753 
1754   if (str == NULL) return;
1755   ptr = str;
1756   ch = *ptr;
1757   while (ch != '\0') {
1758     if (ch == '.')
1759       *ptr = ' ';
1760     ptr++;
1761     ch = *ptr;
1762   }
1763 }
1764 
1765 /*==================================================================*/
1766 /*                                                                  */
1767 /*  ChangeMeshSlashSymbol () -                                      */
1768 /*                                                                  */
1769 /*==================================================================*/
1770 
1771 static void ChangeMeshSlashSymbol (CharPtr str)
1772 
1773 {
1774   Char     ch;
1775   CharPtr  ptr;
1776 
1777   if (str == NULL) return;
1778 
1779   ptr = str;
1780   ch = *ptr;
1781   while (ch != '\0') {
1782     if (ch == '/')
1783       *ptr = '\31';
1784     ptr++;
1785     ch = *ptr;
1786   }
1787 }
1788 
1789 /*==================================================================*/
1790 /*                                                                  */
1791 /*  FindLineOfText () - Assumes a string of text separated by       */
1792 /*                     newline, characters, and terminated by a     */
1793 /*                     newline                                      */
1794 /*                                                                  */
1795 /*==================================================================*/
1796 
1797 static Int2 FindLineOfText (CharPtr text, CharPtr str)
1798 
1799 {
1800   Char          ch;
1801   Int2          compare, idx, left, mid, numLines, right;
1802   CharPtr PNTR  index;
1803   CharPtr       lookfor, ptr;
1804   size_t        len;
1805 
1806   /* Check parameters */
1807 
1808   if (StringLen (text) == 0 || StringLen (str) == 0) return 0;
1809 
1810   /* Count the number of lines to be searched */
1811 
1812   mid = 0;
1813   lookfor = StringSave (str);
1814   ChangeMeshSlashSymbol (lookfor);
1815   numLines = 0;
1816   ptr = text;
1817   ch = *ptr;
1818   while (ch != '\0') {
1819     if (ch == '\n')
1820       numLines++;
1821     ptr++;
1822     ch = *ptr;
1823   }
1824 
1825   if (numLines <= 0) {
1826     MemFree (lookfor);
1827     return 0;
1828   }
1829 
1830   /* Create an array of pointers to the lines */
1831 
1832   index = MemNew (sizeof (CharPtr) * (size_t) (numLines + 3));
1833   if (index != NULL) {
1834     idx = 0;
1835     ptr = text;
1836     ch = *ptr;
1837     index [idx] = ptr;
1838     while (ch != '\0') {
1839       if (ch == '\n') {
1840         idx++;
1841         *ptr = '\0';
1842         ptr++;
1843         ch = *ptr;
1844         index [idx] = ptr;
1845       } else {
1846         ptr++;
1847         ch = *ptr;
1848       }
1849     }
1850   }
1851 
1852   /* Do a binary search for the search string */
1853 
1854   if (index != NULL) {
1855     left = 1;
1856     right = numLines;
1857     while (left <= right) {
1858       mid = (left + right) / 2;
1859       compare = StringICmp (lookfor, index [mid - 1]);
1860       if (compare <= 0)
1861         right = mid - 1;
1862       if (compare >= 0)
1863         left = mid + 1;
1864     }
1865 
1866     if (left <= right + 1) {
1867       len = StringLen (lookfor);
1868       compare = StringNICmp (lookfor, index [mid - 1], len);
1869       if (compare > 0) {
1870         mid++;
1871         /*
1872         if (mid <= numLines) {
1873       compare = StringNICmp (lookfor, index [mid - 1], len);
1874       if (compare > 0)
1875         mid = 0;
1876         } else
1877       mid = 0;
1878         */
1879       }
1880       /*
1881       else
1882         mid = 0;
1883       */
1884     }
1885   }
1886   
1887   /* Clean up and return */
1888 
1889   MemFree (index);
1890   MemFree (lookfor);
1891   return mid;
1892 }
1893 
1894 /*==================================================================*/
1895 /*                                                                  */
1896 /*  ScrollToText () -                                               */
1897 /*                                                                  */
1898 /*==================================================================*/
1899 
1900 static void ScrollToText (FormInfoPtr pFormInfo,
1901               CharPtr     str,
1902               Int2        page,
1903               Boolean     hard,
1904               Boolean     exact)
1905 
1906 {
1907   Int2     compare, oldItem, oldRow, perfect, row;
1908   size_t   len;
1909   Int4     numLines, startsAt;
1910   BaR      sb;
1911   Char     temp [256];
1912   CharPtr  text;
1913 
1914   /* Check parameters */
1915 
1916   if (StringHasNoText (str) || page == 0) return;
1917 
1918   /* Clean up the text string */
1919 
1920   StringNCpy_0 (temp, str, sizeof (temp));
1921   ChangeUnderscoreToSpace (temp);
1922   ChangePeriodToSpace (temp);
1923   ChangeMeshSlashSymbol (temp);
1924 
1925   /* Get the information on the current page of data */
1926 
1927   text = GetDocText (pFormInfo->availDoc, page, 0, 1);
1928   GetItemParams4 (pFormInfo->availDoc, page, &startsAt, NULL, NULL, NULL, NULL);
1929   GetDocParams4 (pFormInfo->availDoc, NULL, &numLines);
1930   ChangeMeshSlashSymbol (text);
1931 
1932   /* Search for the text string in the current page of data */
1933 
1934   row = FindLineOfText (text, temp);
1935   MemFree (text);
1936 
1937   /* If the text string is not on the page */
1938   /* then go to the top of the page.       */
1939 
1940   if (row < 1 || row > numLines)
1941     /*
1942     return;
1943     */
1944     row = 1;
1945 
1946   /* If the term is not on the current page then */
1947   /* we have to load and search the new page.    */
1948 
1949   /*
1950   if (row <= 1 || row >= numLines) {
1951     LoadAvailList (pFormInfo, str);
1952     return;
1953   }
1954   */
1955 
1956   /* Redisplay the page with the text string highlighted */
1957   
1958   startsAt += row - 1;
1959   sb = GetSlateVScrollBar ((SlatE) pFormInfo->availDoc);
1960   CorrectBarMax (sb, numLines - 7);
1961   if (!RowIsVisible (pFormInfo->availDoc, page, row, NULL, NULL)) {
1962     ForceFormat (pFormInfo->availDoc, page);    /* forces UpdateLineStarts */
1963     GetItemParams4 (pFormInfo->availDoc, page, &startsAt, NULL, NULL,
1964             NULL, NULL);
1965     GetDocParams4 (pFormInfo->availDoc, NULL, &numLines);
1966     startsAt += row - 1;
1967     sb = GetSlateVScrollBar ((SlatE) pFormInfo->availDoc);
1968     CorrectBarMax (sb, numLines - 7);
1969     if (hard)
1970       SetBarValue (sb, startsAt);
1971     else
1972       CorrectBarValue (sb, startsAt);
1973   }
1974   text = GetDocText (pFormInfo->availDoc, page, row, 1);
1975   ChangeMeshSlashSymbol (text);
1976   perfect = StringICmp (text, temp);
1977   len = StringLen (temp);
1978   compare = StringNICmp (text, temp, len);
1979   MemFree (text);
1980   if (compare == 0) {
1981     oldItem = pFormInfo->availItem;
1982     oldRow = pFormInfo->availRow;
1983     if (oldItem != page || oldRow != row) {
1984       pFormInfo->availItem = page;
1985       pFormInfo->availRow = row;
1986       InvalDocRows (pFormInfo->availDoc, oldItem, oldRow, oldRow);
1987       InvalDocRows (pFormInfo->availDoc, pFormInfo->availItem,
1988             pFormInfo->availRow, pFormInfo->availRow);
1989     }
1990     if (exact) {
1991       if (perfect == 0)
1992         pFormInfo->textChanged = FALSE;
1993     } else
1994       pFormInfo->textChanged = FALSE;
1995   } else {
1996     pFormInfo->availItem = 0;
1997     pFormInfo->availRow = 0;
1998   }
1999 }
2000 
2001 /*==================================================================*/
2002 /*                                                                  */
2003 /*  LoadAvailList () -                                              */
2004 /*                                                                  */
2005 /*==================================================================*/
2006 
2007 static Boolean LoadAvailList (FormInfoPtr pFormInfo, CharPtr str)
2008 
2009 {
2010   Int4                 count;
2011   Entrez2FieldInfoPtr  fieldInfo;
2012   Int4                 pagesize;
2013   Int2                 numpages = 0;
2014   Int2                 page = 0;
2015 
2016   pFormInfo->availItem = 0;
2017   pFormInfo->availRow = 0;
2018   Reset (pFormInfo->availDoc);
2019   SetDocCache (pFormInfo->availDoc, NULL, NULL, NULL);
2020   Update ();
2021   if (str [0] == '\0') return FALSE;
2022 
2023   fieldInfo = FieldGetInfo (pFormInfo->currDb, pFormInfo->currField);
2024   count = fieldInfo->term_count;
2025   if (count == 0) return FALSE;
2026 
2027   pFormInfo->availNumTerms = count;
2028   pagesize = 1;
2029   while (count > pagesize) {
2030     count /= 2;
2031     pagesize *= 2;
2032   }
2033 
2034   while (count < 16000 && pagesize > 128) {
2035     count *= 2;
2036     pagesize /= 2;
2037   }
2038   pFormInfo->availPageSize = pagesize;
2039   numpages = (Int2) ((pFormInfo->availNumTerms + pagesize - 1) / pagesize);
2040   pFormInfo->availNumPages = numpages;
2041 
2042   BulkAppendItem (pFormInfo->availDoc, numpages, FetchFromTermList, pagesize, &availParFmt, availColFmt, systemFont);
2043   AppendText (pFormInfo->availDoc, "\n\n\n\n\n\n\n\n\n\n\n\n \n", &availParFmt, availColFmt, systemFont);
2044 
2045   SetDocCache (pFormInfo->availDoc, StdPutDocCache, StdGetDocCache, StdResetDocCache);
2046 
2047   page = GetTermPage (pFormInfo, str);
2048   pFormInfo->availCurrentPage = page + 1;
2049   if (page != -1) {
2050     ScrollToText (pFormInfo, str, pFormInfo->availCurrentPage, FALSE, FALSE);
2051   }
2052 
2053   InvalDocument (pFormInfo->availDoc);
2054   Update ();
2055   AdjustDocScroll (pFormInfo->availDoc);
2056 
2057   return TRUE;
2058 }
2059 
2060 /*==================================================================*/
2061 /*                                                                  */
2062 /*  ProcessSelectionTerm () -                                       */
2063 /*                                                                  */
2064 /*==================================================================*/
2065 
2066 static void ProcessSelectionTerm (FormInfoPtr pFormInfo, CharPtr str)
2067 
2068 {
2069   Int4     iTermCount;
2070   Char     termText [E2_STR_BUFF_SIZE];
2071   CharPtr  text;
2072 
2073   /* If a new term has been typed into the */
2074   /* term text entry box, then do a lookup */
2075   /* of that term.                         */
2076 
2077   if (pFormInfo->textChanged) {
2078     LoadAvailList (pFormInfo, str);
2079     pFormInfo->textChanged = FALSE;
2080     pFormInfo->okayToAccept = FALSE;
2081   }
2082 
2083   /* Process the highlighted term from */
2084   /* the term selection box            */
2085 
2086   else if (pFormInfo->okayToAccept &&
2087        pFormInfo->availItem > 0 &&
2088        pFormInfo->availRow > 0) {
2089 
2090     text = GetDocText (pFormInfo->availDoc, pFormInfo->availItem,
2091                pFormInfo->availRow, E2_TERM_COL);
2092     if (NULL == text)
2093       return;
2094 
2095     GetTitle (pFormInfo->termText, termText, E2_STR_BUFF_SIZE);
2096 
2097     /* If the higlighted term is the same as */
2098     /* in the text entry box, then add the   */
2099     /* term to the Query Refinement list.    */
2100 
2101     if (StringICmp (termText, text) == 0) {
2102       if (StringICmp (str, text) == 0) {
2103     MemFree (text);
2104     text = GetDocText (pFormInfo->availDoc, pFormInfo->availItem,
2105                pFormInfo->availRow, E2_COUNT_COL);
2106     TrimSpacesAroundString (text);
2107     StrToLong (text, &iTermCount);
2108     MemFree (text);
2109     Query_AddBoolTerm (pFormInfo->form, pFormInfo->currDb,
2110                pFormInfo->currField, str, STATE_ON,
2111                iTermCount);
2112     Select (pFormInfo->termText);
2113     pFormInfo->okayToAccept = FALSE;
2114       }
2115     }
2116 
2117     /* Otherwise, just move the higlighted */
2118     /* term to the text box.               */
2119 
2120     else {
2121       TrimSpacesAroundString (text);
2122       SafeSetTitle (pFormInfo->termText, text);
2123       Select (pFormInfo->termText);
2124       Update ();
2125       StringNCpy_0 (str, text, E2_STR_BUFF_SIZE);
2126     }
2127 
2128   }
2129 }
2130 
2131 /*==================================================================*/
2132 /*                                                                  */
2133 /*  ProcessTaxonomyTerm () -                                        */
2134 /*                                                                  */
2135 /*==================================================================*/
2136 
2137 static void ProcessTaxonomyTerm (FormInfoPtr pFormInfo, CharPtr str)
2138 
2139 {
2140   Int4     iTermCount;
2141   CharPtr  text;
2142 
2143   /*----------------------*/
2144   /* Get the term's count */
2145   /*----------------------*/
2146 
2147   text = GetDocText (pFormInfo->availDoc, pFormInfo->availItem, pFormInfo->availRow, E2_COUNT_COL);
2148   TrimSpacesAroundString (text);
2149   StrToLong (text, &iTermCount);
2150   MemFree (text);
2151 
2152   /*-----------------------------------*/
2153   /* Add the term to the current query */
2154   /*-----------------------------------*/
2155 
2156   Query_AddBoolTerm (pFormInfo->form, pFormInfo->currDb, pFormInfo->currField, str, STATE_ON, iTermCount);
2157   Select (pFormInfo->termText);
2158   pFormInfo->okayToAccept = FALSE;
2159 }
2160 
2161 /*===================================================================*/
2162 /*                                                                   */
2163 /*  ReadAFew () - Fetches the count for a given term and for several */
2164 /*               following terms and displays them in the term list  */
2165 /*               panel.                                              */
2166 /*                                                                   */
2167 /*===================================================================*/
2168 
2169 static Boolean ReadAFew (FormInfoPtr pFormInfo, CharPtr str, CharPtr actual, size_t maxsize, Int4Ptr count)
2170 
2171 {
2172   Char                 displayStr [256];
2173   Boolean              found;
2174   Entrez2TermListPtr   e2TermListPtr;
2175   Entrez2FieldInfoPtr  fieldInfo;
2176   CharPtr              dbName;
2177   CharPtr              fieldName;
2178   Int2                 row;
2179   Entrez2TermPtr       termPtr;
2180 
2181   /*------------------------------*/
2182   /* Get the names of the current */
2183   /* db and the current field.    */
2184   /*------------------------------*/
2185 
2186   found = FALSE;
2187   dbName = DBGetNameFromID (pFormInfo->currDb);
2188   fieldInfo = FieldGetInfo (pFormInfo->currDb, pFormInfo->currField);
2189   fieldName = fieldInfo->field_name;
2190   if (StringHasNoText (dbName) || StringHasNoText (fieldName)) return FALSE;
2191 
2192   /*----------------------------------------*/
2193   /* Fetch a count for the requested string */
2194   /* and for several strings after it.      */
2195   /*----------------------------------------*/
2196 
2197   e2TermListPtr = Query_FetchSeveralCounts (dbName, fieldName, str, AVAIL_WINDOW_ROWS);
2198 
2199   if (e2TermListPtr == NULL) return FALSE;
2200 
2201   /*-------------------------------*/
2202   /* Did we find the desired term? */
2203   /*-------------------------------*/
2204 
2205   if (StringICmp (e2TermListPtr->list->term, str) == 0) {
2206     found = TRUE;
2207   } else {
2208     found = FALSE;
2209     StringCpy (actual, e2TermListPtr->list->term);
2210   }
2211 
2212   /*----------------------------*/
2213   /* Send the count back to the */
2214   /* calling function.          */
2215   /*----------------------------*/
2216 
2217   *count = e2TermListPtr->list->count;
2218 
2219   /*-------------------------------------*/
2220   /* Display the term and it's neighbors */
2221   /* in the term list window.            */
2222   /*-------------------------------------*/
2223 
2224   termPtr = e2TermListPtr->list;
2225 
2226   for (row = 1, termPtr = e2TermListPtr->list; row <= *count, termPtr != NULL; row++, termPtr = termPtr->next) {
2227     sprintf (displayStr, "%s\t%ld\t%d\n", termPtr->term, (long) (termPtr->count), (int) (termPtr->is_leaf_node ? 1 : 0));
2228     AppendText (pFormInfo->availDoc, displayStr, &availParFmt, availColFmt, systemFont);
2229   }
2230 
2231   if (found) {
2232     pFormInfo->availItem = 1;
2233     pFormInfo->availRow = 1;
2234   }
2235   InvalDocument (pFormInfo->availDoc);
2236 
2237   /*---------------------*/
2238   /* Return successfully */
2239   /*---------------------*/
2240 
2241   return found;
2242 }
2243 
2244 /*==================================================================*/
2245 /*                                                                  */
2246 /*  ProcessMultipleTerms () -                                       */
2247 /*                                                                  */
2248 /*==================================================================*/
2249 
2250 static void ProcessMultipleTerms (FormInfoPtr pFormInfo, CharPtr strs)
2251 
2252 {
2253   Char     actual [256];
2254   Char     ch;
2255   Int4     count = 0;
2256   Boolean  found;
2257   Int2     i;
2258   Int2     j;
2259   Int2     k;
2260   Char     str [256];
2261 
2262   i = 0;
2263   while (StringLen (strs + i) > 0) {
2264 
2265     /*--------------------------------*/
2266     /* Parse a term out of the string */
2267     /*--------------------------------*/
2268 
2269     StringNCpy_0 (str, strs + i, sizeof (str));
2270     k = 0;
2271     ch = str [k];
2272     while (ch == ' ') {
2273       k++;
2274       ch = str [k];
2275     }
2276     j = 0;
2277     if (ch == '"') {
2278       k++;
2279       ch = str [j + k];
2280       while (ch != '\0' && ch != '"') {
2281         j++;
2282         ch = str [j + k];
2283       }
2284       if (ch == '"') {
2285         str [j + k] = '\0';
2286         i += j + k + 1;
2287       } else
2288         i += j + k;
2289     } else {
2290       while (ch != '\0' && ch != ' ') {
2291         j++;
2292         ch = str [j + k];
2293       }
2294       if (ch == ' ') {
2295         str [j + k] = '\0';
2296         i += j + k + 1;
2297       } else
2298         i += j + k;
2299     }
2300 
2301     /*-----------------------------------*/
2302     /* If we successfully parsed a term, */
2303     /* look it up and then add it to the */
2304     /* boolean query if found.           */
2305     /*-----------------------------------*/
2306 
2307     if (StringLen (str + k) > 0) {
2308       pFormInfo->availItem = 0;
2309       pFormInfo->availRow = 0;
2310       Reset (pFormInfo->availDoc);
2311       actual [0] = '\0';
2312       found = ReadAFew (pFormInfo, str + k, actual, sizeof (actual), &count);
2313       Update ();
2314       if (found) {
2315         Query_AddBoolTerm (pFormInfo->form, pFormInfo->currDb, pFormInfo->currField, str + k, STATE_ON, count);
2316       } else {
2317         Query_AddBoolTerm (pFormInfo->form, pFormInfo->currDb, pFormInfo->currField, actual, STATE_OFF, count);
2318       }
2319     }
2320   }
2321 
2322   /*-------------------------------------*/
2323   /* Clear out the term selection window */
2324   /* and the term entry fields.          */
2325   /*-------------------------------------*/
2326 
2327   pFormInfo->availItem = 0;
2328   pFormInfo->availRow = 0;
2329   Reset (pFormInfo->availDoc);
2330 
2331   InvalDocument (pFormInfo->availDoc);
2332   SafeSetTitle (pFormInfo->termText, "");
2333   SafeSetTitle (pFormInfo->fromText, "");
2334   SafeSetTitle (pFormInfo->toText, "");
2335   SafeDisable (pFormInfo->acceptButton);
2336   if (Visible (pFormInfo->termText)) {
2337     Select (pFormInfo->termText);
2338   }
2339 }
2340 
2341 /*==================================================================*/
2342 /*                                                                  */
2343 /*  RecalculateChosen () -                                          */
2344 /*                                                                  */
2345 /*==================================================================*/
2346 
2347 static void RecalculateChosen (FormInfoPtr pFormInfo)
2348 
2349 {
2350   Int4  count;
2351   Char  tmp [32];
2352 
2353   /*-------------------------------*/
2354   /* Get a count of documents that */
2355   /* satisfy the current query.    */
2356   /*-------------------------------*/
2357 
2358   count = Query_FetchCount (pFormInfo->form);
2359 
2360   /*-----------------------------------*/
2361   /* Update the retrieve message count */
2362   /*-----------------------------------*/
2363 
2364   if (count < 1)
2365     sprintf (tmp, "Retrieve 0 Documents");
2366   else if (count > 1)
2367     sprintf (tmp, "Retrieve %ld Documents", (long) count);
2368   else
2369     sprintf (tmp, "Retrieve %ld Document", (long) count);
2370 
2371   SafeSetTitle (pFormInfo->retrieveButton, tmp);
2372   SafeSetTitle (pFormInfo->advRetrieveButton, tmp);
2373 
2374   if (count < 1 || count > 32000) {
2375     SafeDisable (pFormInfo->retrieveButton);
2376     SafeDisable (pFormInfo->advRetrieveButton);
2377   } else {
2378     SafeEnable (pFormInfo->retrieveButton);
2379     SafeEnable (pFormInfo->advRetrieveButton);
2380   }
2381 }
2382 
2383 /*==================================================================*/
2384 /*                                                                  */
2385 /*  Query_TruncateCount () -                                        */
2386 /*                                                                  */
2387 /*==================================================================*/
2388 
2389 static Int4 Query_TruncateCount (FormInfoPtr pFormInfo, CharPtr str)
2390 
2391 {
2392   CharPtr                 dbName;
2393   Boolean                 doNotExplode;
2394   Boolean                 doNotTranslate;
2395   Int4                    count;
2396   Entrez2RequestPtr       e2RequestPtr;
2397   Entrez2ReplyPtr         e2ReplyPtr;
2398   Entrez2BooleanReplyPtr  e2BooleanPtr;
2399   Entrez2FieldInfoPtr     fieldInfo;
2400 
2401   if (pFormInfo == NULL || StringHasNoText (str)) return 0;
2402 
2403   /*--------------------------------*/
2404   /* Get the name of the current DB */
2405   /*--------------------------------*/
2406 
2407   dbName = DBGetNameFromID (pFormInfo->currDb);
2408   if (StringHasNoText (dbName)) return 0;
2409 
2410   fieldInfo = FieldGetInfo (pFormInfo->currDb, pFormInfo->currField);
2411   if (fieldInfo == NULL) return 0;
2412 
2413   /*---------------------------------*/
2414   /* Create an empty Boolean request */
2415   /*---------------------------------*/
2416 
2417   e2RequestPtr = EntrezCreateBooleanRequest (FALSE, FALSE, dbName, NULL, 0, 0, NULL, 0, 0);
2418   if (e2RequestPtr == NULL) return 0;
2419 
2420   /*--------------------------------------------------*/
2421   /* Send truncated term count request to the server. */
2422   /*--------------------------------------------------*/
2423 
2424   doNotTranslate = FALSE;
2425   doNotExplode = !GetStatus (pFormInfo->explodeItem);
2426   EntrezAddToBooleanRequest (e2RequestPtr, NULL, 0, fieldInfo->field_name,
2427                              str, NULL, 0, 0, NULL, NULL,
2428                              doNotExplode, doNotTranslate);
2429 
2430   if (ShowASN () == TRUE)
2431     DisplayEntrezRequest (e2RequestPtr);
2432 
2433   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
2434 
2435   if (ShowASN () == TRUE)
2436     DisplayEntrezReply (e2ReplyPtr);
2437 
2438   if (e2ReplyPtr == NULL) return 0;
2439 
2440   /*----------------------------------*/
2441   /* Parse the count out of the reply */
2442   /*----------------------------------*/
2443 
2444   e2BooleanPtr = EntrezExtractBooleanReply (e2ReplyPtr);
2445   count = e2BooleanPtr->count;
2446 
2447   /*----------------------------------*/
2448   /* Clean up and return successfully */
2449   /*----------------------------------*/
2450 
2451   Entrez2BooleanReplyFree (e2BooleanPtr);
2452   Entrez2RequestFree (e2RequestPtr);
2453 
2454   return count;
2455 }
2456 
2457 /*==================================================================*/
2458 /*                                                                  */
2459 /*  Query_FetchRangeCount () -                                      */
2460 /*                                                                  */
2461 /*==================================================================*/
2462 
2463 static Int4 Query_FetchRangeCount (FormInfoPtr pFormInfo, CharPtr str)
2464 
2465 {
2466   CharPtr                 dbName;
2467   Int4                    count;
2468   Entrez2RequestPtr       e2RequestPtr;
2469   Entrez2ReplyPtr         e2ReplyPtr;
2470   Entrez2BooleanReplyPtr  e2BooleanPtr;
2471   Entrez2FieldInfoPtr     fieldInfo;
2472   Boolean                 doNotTranslate;
2473 
2474   if (pFormInfo == NULL || StringHasNoText (str)) return 0;
2475 
2476   /*--------------------------------*/
2477   /* Get the name of the current DB */
2478   /*--------------------------------*/
2479 
2480   dbName = DBGetNameFromID (pFormInfo->currDb);
2481   if (StringHasNoText (dbName)) return 0;
2482 
2483   fieldInfo = FieldGetInfo (pFormInfo->currDb, pFormInfo->currField);
2484   if (fieldInfo == NULL) return 0;
2485 
2486   /*---------------------------------*/
2487   /* Create an empty Boolean request */
2488   /*---------------------------------*/
2489 
2490   e2RequestPtr = EntrezCreateBooleanRequest (FALSE, FALSE, dbName, NULL, 0, 0, NULL, 0, 0);
2491   if (e2RequestPtr == NULL) return 0;
2492 
2493   /*--------------------------------------------------*/
2494   /* Send truncated term count request to the server. */
2495   /*--------------------------------------------------*/
2496 
2497   doNotTranslate = FALSE;
2498   EntrezAddToBooleanRequest (e2RequestPtr, NULL, 0, fieldInfo->field_name, str, NULL, 0, 0, NULL, NULL, FALSE, doNotTranslate);
2499 
2500   if (ShowASN () == TRUE)
2501     DisplayEntrezRequest (e2RequestPtr);
2502 
2503   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
2504 
2505   if (ShowASN () == TRUE)
2506     DisplayEntrezReply (e2ReplyPtr);
2507 
2508   if (e2ReplyPtr == NULL) return 0;
2509 
2510   /*----------------------------------*/
2511   /* Parse the count out of the reply */
2512   /*----------------------------------*/
2513 
2514   e2BooleanPtr = EntrezExtractBooleanReply (e2ReplyPtr);
2515   if (e2BooleanPtr != NULL)
2516     count = e2BooleanPtr->count;
2517   else {
2518     Entrez2RequestFree (e2RequestPtr);
2519     return 0;
2520   }
2521     
2522 
2523   /*----------------------------------*/
2524   /* Clean up and return successfully */
2525   /*----------------------------------*/
2526 
2527   Entrez2BooleanReplyFree (e2BooleanPtr);
2528   Entrez2RequestFree (e2RequestPtr);
2529 
2530   return count;
2531 }
2532 
2533 /*===================================================================*/
2534 /*                                                                   */
2535 /* ProcessRangeTerms ()                                              */
2536 /*                                                                   */
2537 /*===================================================================*/
2538 
2539 static void ProcessRangeTerms (FormInfoPtr pFormInfo)
2540 {
2541   Char          fromStr [E2_STR_BUFF_SIZE];
2542   Char          toStr [E2_STR_BUFF_SIZE];
2543   Char          rangeStr [2 * E2_STR_BUFF_SIZE + 1];
2544   StateDataPtr  sdp;
2545   Int4          count;
2546   CharPtr       text;
2547 
2548   /* If a new term has been typed into the */
2549   /* 'To' text box, then do a lookup of    */
2550   /* that term.                            */
2551 
2552   if (pFormInfo->isToTextChanged) {
2553     GetTitle (pFormInfo->toText, toStr, E2_STR_BUFF_SIZE);
2554     pFormInfo->isValidTo = LoadAvailList (pFormInfo, toStr);
2555     pFormInfo->isToTextChanged = FALSE;
2556   }
2557   /* If we have valid 'From' and 'To' terms then */
2558   /* create a range term in the query window.    */
2559 
2560   else if ((pFormInfo->isValidFrom) && (pFormInfo->isValidTo)) {
2561 
2562     /* Get the 'from' and 'to' strings */
2563 
2564     GetTitle (pFormInfo->toText, toStr, E2_STR_BUFF_SIZE);
2565     GetTitle (pFormInfo->fromText, fromStr, E2_STR_BUFF_SIZE);
2566     sprintf(rangeStr, "%s:%s", fromStr, toStr);
2567     
2568     /* Get a count for the range */
2569     
2570     count = Query_FetchRangeCount (pFormInfo, rangeStr);
2571     
2572     /*  Add a term to the linked list */
2573     
2574     sdp = CreateTerm (pFormInfo->form, pFormInfo->currDb,
2575                       pFormInfo->currField, rangeStr, STATE_ON, count,
2576                       FALSE);
2577     if (NULL == sdp)
2578       return;
2579     
2580     /* Display the range as one term */
2581     
2582     DisplayTerm (pFormInfo, rangeStr, sdp->field, sdp->count);
2583     
2584     Select (pFormInfo->fromText);
2585     Reset (pFormInfo->availDoc);
2586     pFormInfo->okayToAccept = FALSE;
2587   }
2588 
2589   /* If a new term has been typed into the */
2590   /* 'From' text box, then do a lookup of  */
2591   /* that term.                            */
2592 
2593   else if (pFormInfo->isFromTextChanged) {
2594     GetTitle (pFormInfo->fromText, fromStr, E2_STR_BUFF_SIZE);
2595     pFormInfo->isValidFrom = LoadAvailList (pFormInfo, fromStr);
2596     pFormInfo->isFromTextChanged = FALSE;
2597   }
2598     
2599   else if (pFormInfo->okayToAccept &&
2600            pFormInfo->availItem > 0 &&
2601            pFormInfo->availRow > 0) {
2602     text = GetDocText (pFormInfo->availDoc, pFormInfo->availItem,
2603                        pFormInfo->availRow, E2_TERM_COL);
2604     if (text != NULL) {
2605       TrimSpacesAroundString (text);
2606       if (pFormInfo->currRangeField == E2_RANGE_FROM) {
2607         SafeSetTitle (pFormInfo->fromText, text);
2608         Select (pFormInfo->fromText);
2609         pFormInfo->isValidFrom = TRUE;
2610         pFormInfo->isFromTextChanged = FALSE;
2611       }
2612       else {
2613         SafeSetTitle (pFormInfo->toText, text);
2614         Select (pFormInfo->toText);
2615         pFormInfo->isValidTo = TRUE;
2616         pFormInfo->isToTextChanged = FALSE;
2617       }
2618       Update ();
2619     }
2620     MemFree (text);
2621   }
2622 
2623   /* Return successfully */
2624   
2625   return;
2626 }
2627 
2628 /*===================================================================*/
2629 /*                                                                   */
2630 /*  Accept_Callback () - Called when the accept button is pressed,   */
2631 /*                      if fetches a term list or adds term to query */
2632 /*                      list.                                        */
2633 /*                                                                   */
2634 /*===================================================================*/
2635 
2636 static void Accept_Callback (ButtoN b)
2637 
2638 {
2639   Int4          count;
2640   FormInfoPtr   pFormInfo;
2641   StateDataPtr  sdp;
2642   Char          str [E2_STR_BUFF_SIZE];
2643 
2644   pFormInfo = (FormInfoPtr) GetObjectExtra (b);
2645 
2646   str [0] = '\0';
2647   if (pFormInfo->currMode == RANGE_MODE)
2648     GetTitle (CurrentText (), str, E2_STR_BUFF_SIZE);
2649   else
2650     GetTitle (pFormInfo->termText, str, E2_STR_BUFF_SIZE);
2651   if (str [0] == '\0') return;
2652 
2653   WatchCursor ();
2654   switch (pFormInfo->currMode) {
2655     case TRANSLATE_MODE:
2656       Query_TranslateAndAddBoolTerm (pFormInfo->form, pFormInfo->currDb,
2657                      pFormInfo->currField, str, STATE_ON, 0);
2658       SafeSetTitle (pFormInfo->termText, "");
2659       if (Visible (pFormInfo->termText))
2660         Select (pFormInfo->termText);
2661       pFormInfo->availItem = 0;
2662       pFormInfo->availRow = 0;
2663       Reset (pFormInfo->availDoc);
2664       break;
2665     case SELECTION_MODE:
2666       ProcessSelectionTerm (pFormInfo, str);
2667       /*
2668       pFormInfo->availCurrentPage = 0;
2669       */
2670       break;
2671     case AUTOMATIC_MODE:
2672       ProcessMultipleTerms (pFormInfo, str);
2673       break;
2674     case WILD_CARD_MODE:
2675       StringCat (str, "*");
2676       count = Query_TruncateCount (pFormInfo, str);
2677       sdp = CreateTerm (pFormInfo->form, pFormInfo->currDb,
2678                         pFormInfo->currField, str, STATE_ON, count, FALSE);
2679       if (sdp != NULL) {
2680         DisplayTerm (pFormInfo, str, sdp->field, count);
2681       }
2682       SafeSetTitle (pFormInfo->termText, "");
2683       if (Visible (pFormInfo->termText))
2684         Select (pFormInfo->termText);
2685       pFormInfo->availItem = 0;
2686       pFormInfo->availRow = 0;
2687       Reset (pFormInfo->availDoc);
2688       break;
2689     case MESH_TREE_MODE:
2690       ProcessMeshTerm (pFormInfo, str);
2691       break;
2692     case TAXONOMY_MODE:
2693       ProcessTaxonomyTerm (pFormInfo, str);
2694       break;
2695     case RANGE_MODE:
2696       ProcessRangeTerms (pFormInfo);
2697       break;
2698     case LOOKUP_ACCN_MODE:
2699     case LOOKUP_UID_MODE:
2700     case VIEW_ACCN_MODE:
2701     case VIEW_UID_MODE:
2702       ProcessDirectLookup (pFormInfo, str);
2703       ArrowCursor ();
2704       Update ();
2705       return;
2706     default:
2707       break;
2708   }
2709   Update ();
2710 
2711   RecalculateChosen (pFormInfo);
2712 
2713   ArrowCursor ();
2714   Update ();
2715 }
2716 
2717 /*===================================================================*/
2718 /*                                                                   */
2719 /*  EvaluateRetrieve_Callback () - This is the callback for the      */
2720 /*                                Evaluate/Retrieve button in        */
2721 /*                                advanced query mode.               */
2722 /*                                                                   */
2723 /*===================================================================*/
2724 
2725 static void EvaluateRetrieve_Callback (ButtoN evaluateRetrieveButton)
2726 
2727 {
2728   FormInfoPtr  pFormInfo;
2729 
2730   pFormInfo = (FormInfoPtr) GetObjectExtra (evaluateRetrieveButton);
2731 
2732   if (pFormInfo->advQueryState == ADV_QUERY_EVALUATE_STATE) {
2733     WatchCursor ();
2734     Update ();
2735     RecalculateChosen (pFormInfo);
2736     pFormInfo->advQueryState = ADV_QUERY_RETRIEVE_STATE;
2737     ArrowCursor ();
2738   } else if (pFormInfo->advQueryState == ADV_QUERY_RETRIEVE_STATE) {
2739     pFormInfo->retrieveDocsProc (evaluateRetrieveButton);
2740     pFormInfo->advQueryState = ADV_QUERY_INVALID_STATE;
2741   }
2742 }
2743 
2744 /*===================================================================*/
2745 /*                                                                   */
2746 /*  DatabaseView_Callback () and FieldView_Callback () -             */
2747 /*     Callback functions for items in Help menu.                    */
2748 /*                                                                   */
2749 /*===================================================================*/
2750 
2751 static void DatabaseView_Callback (IteM i)
2752 
2753 {
2754   Entrez2DbInfoPtr  e2db;
2755   Entrez2InfoPtr    e2ip;
2756   FILE              *fp;
2757   Int2              len;
2758   Int2              max_menu = 0;
2759   Int2              max_name = 0;
2760   Char              path [PATH_MAX];
2761 
2762   e2ip = Query_GetInfo ();
2763   if (e2ip == NULL) return;
2764   TmpNam (path);
2765   fp = FileOpen (path, "w");
2766   if (fp == NULL) return;
2767   for (e2db = e2ip->db_info; e2db != NULL; e2db = e2db->next) {
2768     len = (Int2) StringLen (e2db->db_name);
2769     max_name = MAX (len, max_name);
2770     len = (Int2) StringLen (e2db->db_menu);
2771     max_menu = MAX (len, max_menu);
2772   }
2773   max_name += 2;
2774   max_menu += 2;
2775   for (e2db = e2ip->db_info; e2db != NULL; e2db = e2db->next) {
2776     len = (Int2) StringLen (e2db->db_name);
2777     max_name = MAX (len, max_name);
2778     len = (Int2) StringLen (e2db->db_menu);
2779     max_menu = MAX (len, max_menu);
2780   }
2781   for (e2db = e2ip->db_info; e2db != NULL; e2db = e2db->next) {
2782     len = (Int2) StringLen (e2db->db_name);
2783     fprintf (fp, "%s", e2db->db_name);
2784     while (len < max_name) {
2785       fprintf (fp, " ");
2786       len++;
2787     }
2788     len = (Int2) StringLen (e2db->db_menu);
2789     fprintf (fp, "%s", e2db->db_menu);
2790     while (len < max_menu) {
2791       fprintf (fp, " ");
2792       len++;
2793     }
2794     fprintf (fp, "%s", e2db->db_descr);
2795     fprintf (fp, "\n");
2796   }
2797   FileClose (fp);
2798   LaunchGeneralTextViewer (path, "Database Summary");
2799   FileRemove (path);
2800 }
2801 
2802 static void FieldView_Callback (IteM i)
2803 
2804 {
2805   Entrez2InfoPtr       e2ip;
2806   EnumFieldAssocPtr    fieldAlist;
2807   Entrez2FieldInfoPtr  fieldInfo;
2808   FILE                 *fp;
2809   Int2                 j;
2810   Int2                 len;
2811   Int2                 max_menu = 0;
2812   Int2                 max_name = 0;
2813   Char                 path [PATH_MAX];
2814 
2815   e2ip = Query_GetInfo ();
2816   if (e2ip == NULL) return;
2817   fieldAlist = CreateAllFieldsAlist (e2ip);
2818   if (fieldAlist == NULL) return;
2819   TmpNam (path);
2820   fp = FileOpen (path, "w");
2821   if (fp == NULL) return;
2822   for (j = 0; fieldAlist [j].name != NULL; j++) {
2823     fieldInfo = FieldGetInfoFromName (fieldAlist [j].name);
2824     len = (Int2) StringLen (fieldInfo->field_name);
2825     max_name = MAX (len, max_name);
2826     len = (Int2) StringLen (fieldInfo->field_menu);
2827     max_menu = MAX (len, max_menu);
2828   }
2829   max_name += 2;
2830   max_menu += 2;
2831   for (j = 0; fieldAlist [j].name != NULL; j++) {
2832     fieldInfo = FieldGetInfoFromName (fieldAlist [j].name);
2833     len = (Int2) StringLen (fieldInfo->field_name);
2834     fprintf (fp, "%s", fieldInfo->field_name);
2835     while (len < max_name) {
2836       fprintf (fp, " ");
2837       len++;
2838     }
2839     len = (Int2) StringLen (fieldInfo->field_menu);
2840     fprintf (fp, "%s", fieldInfo->field_menu);
2841     while (len < max_menu) {
2842       fprintf (fp, " ");
2843       len++;
2844     }
2845     fprintf (fp, "%s", fieldInfo->field_descr);
2846     fprintf (fp, "\n");
2847   }
2848   FileClose (fp);
2849   LaunchGeneralTextViewer (path, "Field Summary");
2850   FileRemove (path);
2851   FreeEnumFieldAlist (fieldAlist);
2852 }
2853 
2854 static CharPtr modeSummary [] = {
2855   "Automatic  Terms are processed through PubMed query engine",
2856   "Lookup     Accession looked up directly into Document window",
2857   "MeSH Tree  MeSH hierarchy above current level displayed in popup",
2858   "Multiple   Terms extracted and processed one at a time",
2859   "Range      From and To values entered as a composite term",
2860   "Selection  Available terms are displayed in Term Selection box",
2861   "Taxonomy   Organism hierarchy above current level displayed in popup",
2862   "View       Accession looked up directly into Viewer window",
2863   "Wild Card  Term appended with asterisk and processed",
2864   NULL
2865 };
2866 
2867 static void ModeView_Callback (IteM i)
2868 
2869 {
2870   FILE  *fp;
2871   Int2  j;
2872   Char  path [PATH_MAX];
2873 
2874   TmpNam (path);
2875   fp = FileOpen (path, "w");
2876   if (fp == NULL) return;
2877   for (j = 0; modeSummary [j] != NULL; j++) {
2878     fprintf (fp, "%s\n", modeSummary [j]);
2879   }
2880   FileClose (fp);
2881   LaunchGeneralTextViewer (path, "Mode Summary");
2882   FileRemove (path);
2883 }
2884 
2885 /*==================================================================*/
2886 /*                                                                  */
2887 /*  AddPopupItem () - Add an item to a popup list. This is used to  */
2888 /*                   create the lineage popup list in taxonomy      */
2889 /*                   mode.                                          */
2890 /*                                                                  */
2891 /*==================================================================*/
2892 
2893 static void AddPopupItem (PopuP p, CharPtr str, Int2 maxwid)
2894 
2895 {
2896   Char     ch;
2897   Int2     hbounds;
2898   Int2     i;
2899   CharPtr  ptr;
2900   Char     title [256];
2901   Int2     wid;
2902 
2903   if (p != NULL && str != NULL) {
2904     StringNCpy_0 (title, str, sizeof (title));
2905     i = StringLen (title);
2906     title [i] = '\0';
2907     ptr = title;
2908     ch = *ptr;
2909     while (ch != '\0') {
2910       if (ch == '/') {
2911         *ptr = '-';
2912       }
2913       ptr++;
2914       ch = *ptr;
2915     }
2916 #ifdef WIN_MAC
2917     hbounds = 13;
2918 #endif
2919 #ifdef WIN_MSWIN
2920     hbounds = 13;
2921 #endif
2922 #ifdef WIN_MOTIF
2923     hbounds = 24;
2924 #endif
2925     maxwid -= StringWidth ("...") + hbounds * 2 + StringWidth (" ");
2926     wid = 0;
2927     i = 0;
2928     ch = title [i];
2929     while (ch != '\0' && wid <= maxwid) {
2930       wid += CharWidth (ch);
2931       i++;
2932       ch = title [i];
2933     }
2934     title [i] = '\0';
2935     if (ch != '\0' && i <= (Int2) StringLen (str)) {
2936       StringCat (title, "...");
2937     }
2938     PopupItem (p, title);
2939   }
2940 }
2941 
2942 /*==================================================================*/
2943 /*                                                                  */
2944 /*  AvailGetColWidth () - Returns the pixel width of the given      */
2945 /*                       column.                                    */
2946 /*                                                                  */
2947 /*==================================================================*/
2948 
2949 static Int2 AvailGetColWidth (Int2 columnNum)
2950 
2951 {
2952   return availColFmt [columnNum].pixWidth;
2953 }
2954 
2955 /*==================================================================*/
2956 /*                                                                  */
2957 /*  RepopulateTaxonomy () - Given a term and a database, will       */
2958 /*                         look up the term in the taxonomy tree    */
2959 /*                         and populate the Term Selection window   */
2960 /*                         with the term's 'children' in the tree.  */
2961 /*                                                                  */
2962 /*==================================================================*/
2963 
2964 static Boolean RepopulateTaxonomy (FormInfoPtr pFormInfo, CharPtr taxterm)
2965 
2966 {
2967   CharPtr              aLineage [MAX_TAXONOMY_TREE_DEPTH];
2968   Int2                 delta;
2969   CharPtr              dbName;
2970   CharPtr              fieldName;
2971   Int2                 i;
2972   Int2                 maxwidth;
2973   RecT                 r;
2974   RecT                 s;
2975   Char                 str [256];
2976   Int4                 taxId;
2977   Int2                 wid;
2978   Entrez2TermPtr       childPtr;
2979   Entrez2RequestPtr    e2Request;
2980   Entrez2ReplyPtr      e2Reply;
2981   Entrez2HierNodePtr   e2TermNode;
2982   Entrez2TermPtr       currentLineage = NULL;
2983   Entrez2FieldInfoPtr  fieldInfo;
2984 
2985   /*--------------------------*/
2986   /* Build an Entrez2 request */
2987   /*--------------------------*/
2988 
2989   taxId = 0;
2990   dbName = DBGetNameFromID (pFormInfo->currDb);
2991   fieldInfo = FieldGetInfo (pFormInfo->currDb, pFormInfo->currField);
2992   fieldName = fieldInfo->field_name;
2993   if (StringHasNoText (dbName) || StringHasNoText (fieldName)) return FALSE;
2994 
2995   e2Request = EntrezCreateGetTermHierarchyRequest (dbName, fieldName, taxterm, taxId);
2996 
2997   /*----------------------------------*/
2998   /* Send off the request and extract */
2999   /* the resulting reply.             */
3000   /*----------------------------------*/
3001 
3002   if (ShowASN () == TRUE)
3003     DisplayEntrezRequest (e2Request);
3004 
3005   e2Reply = SpecialEntrezSynchronousQuery (e2Request);
3006 
3007   if (ShowASN () == TRUE)
3008     DisplayEntrezReply (e2Reply);
3009 
3010   if (e2Reply == NULL) {
3011     Show (pFormInfo->taxLineagePopup);
3012     Update ();
3013     return FALSE;
3014   }
3015 
3016   e2TermNode = EntrezExtractHierNodeReply (e2Reply);
3017   if (e2TermNode == NULL) {
3018     Show (pFormInfo->taxLineagePopup);
3019     Update ();
3020     return FALSE;
3021   }
3022 
3023   Entrez2RequestFree (e2Request);
3024 
3025   /*-------------------------*/
3026   /* Clear any old terms out */
3027   /* of the Avail window.    */
3028   /*-------------------------*/
3029 
3030   SafeSetTitle (pFormInfo->termText, taxterm);
3031   Hide (pFormInfo->taxLineagePopup);
3032   Reset (pFormInfo->taxLineagePopup);
3033   pFormInfo->taxStrings = ValNodeFreeData (pFormInfo->taxStrings);
3034   pFormInfo->availItem = 0;
3035   pFormInfo->availRow = 0;
3036   Reset (pFormInfo->availDoc);
3037   SetDocCache (pFormInfo->availDoc, NULL, NULL, NULL);
3038   Update ();
3039   maxwidth = AvailGetColWidth (0);
3040 
3041   /*------------------------------------------------*/
3042   /* Create a selection list of a term's "lineage"  */
3043   /*    NOTE: The lineage is provided in the        */
3044   /*          reverse order from how we want to     */
3045   /*          add it to the list box, so they must  */
3046   /*          be put into a random-access structure */
3047   /*          and then reverse added.               */
3048   /*------------------------------------------------*/
3049 
3050   for (i = 0; i < e2TermNode->lineage_count; i++) {
3051     if (i == 0)
3052       currentLineage = e2TermNode->lineage;
3053     else
3054       currentLineage = currentLineage->next;
3055 
3056     if (currentLineage == NULL)
3057       break;
3058 
3059     aLineage [i] = currentLineage->term;
3060   }
3061 
3062   for (i = e2TermNode->lineage_count - 1; i >= 0; i--) {
3063     AddPopupItem (pFormInfo->taxLineagePopup, aLineage [i], maxwidth);
3064     ValNodeCopyStr (&(pFormInfo->taxStrings), 0, aLineage [i]);
3065   }
3066 
3067   /*----------------------------------------------*/
3068   /* Adjust the size of the Pull Down list box to */
3069   /* accomodate the lineage list just created.    */
3070   /*----------------------------------------------*/
3071 
3072   SetValue (pFormInfo->taxLineagePopup, e2TermNode->lineage_count);
3073   ObjectRect (pFormInfo->taxLineagePopup, &r);
3074   ObjectRect (pFormInfo->availDoc, &s);
3075   InsetRect (&s, 4, 4);
3076   wid = r.right - r.left;
3077   delta = (maxwidth - wid) / 2;
3078   r.left = s.left + delta;
3079   r.right = r.left + wid;
3080   SetPosition (pFormInfo->taxLineagePopup, &r);
3081 
3082   /*---------------------------------*/
3083   /* Add the children of the current */
3084   /* term to the Selection Box.      */
3085   /*---------------------------------*/
3086 
3087   childPtr = e2TermNode->children;
3088 
3089   for (i = 0; i < e2TermNode->child_count; i++) {
3090     sprintf (str, "%s\t%ld\t%d\n", childPtr->term, (long) (childPtr->count), (int) (childPtr->is_leaf_node ? 1 : 0));
3091     AppendText (pFormInfo->availDoc, str, &availParFmt, availColFmt, systemFont);
3092     childPtr = childPtr->next;
3093   }
3094 
3095   for (i = e2TermNode->child_count; i < 7; i++)
3096     AppendText (pFormInfo->availDoc, " \n", &availParFmt, availColFmt, systemFont);
3097 
3098   /*-------------------------*/
3099   /* Redraw the avail window */
3100   /* with the new terms.     */
3101   /*-------------------------*/
3102 
3103   InvalDocument (pFormInfo->availDoc);
3104   Show (pFormInfo->taxLineagePopup);
3105   Update ();
3106   AdjustDocScroll (pFormInfo->availDoc);
3107 
3108   return TRUE;
3109 }
3110 
3111 /*==================================================================*/
3112 /*                                                                  */
3113 /*  RepopulateTaxonomyRoot () -                                     */
3114 /*                                                                  */
3115 /*==================================================================*/
3116 
3117 static void RepopulateTaxonomyRoot (FormInfoPtr pFormInfo)
3118 
3119 {
3120   CharPtr  dbName;
3121 
3122   dbName = DBGetNameFromID (pFormInfo->currDb);
3123 
3124   if (StringICmp (dbName, "PubMed") == 0) {
3125     RepopulateTaxonomy (pFormInfo, "All MeSH Categories");
3126   } else {
3127     RepopulateTaxonomy (pFormInfo, "root");
3128   }
3129 }
3130 
3131 /*===================================================================*/
3132 /*                                                                   */
3133 /*  ChangeTaxParents_Callback () - Called when a 'Parent' term is    */
3134 /*                                selected from the taxonomy lineage */
3135 /*                                popup list.                        */
3136 /*                                                                   */
3137 /*                                Makes the selected term the active */
3138 /*                                one and re-queries for it.         */
3139 /*                                                                   */
3140 /*===================================================================*/
3141 
3142 static void ChangeTaxParents_Callback (PopuP p)
3143 
3144 {
3145   FormInfoPtr  pFormInfo;
3146   Int2         val;
3147   ValNodePtr   vnp;
3148 
3149   pFormInfo = (FormInfoPtr) GetObjectExtra (p);
3150 
3151   val = GetValue (p);
3152   if (val <= 0) return;
3153 
3154   vnp = pFormInfo->taxStrings;
3155   while (val > 1 && vnp != NULL) {
3156     val--;
3157     vnp = vnp->next;
3158   }
3159   if (vnp != NULL) {
3160     WatchCursor ();
3161     RepopulateTaxonomy (pFormInfo, (CharPtr) vnp->data.ptrvalue);
3162     ArrowCursor ();
3163   }
3164 }
3165 
3166 /*===================================================================*/
3167 /*                                                                   */
3168 /*  TextAction () - Called when a key is type into the "Term:" text  */
3169 /*                  entry box.  Enables/disables the accept button   */
3170 /*                  and scroll to text.                              */
3171 /*                                                                   */
3172 /*===================================================================*/
3173 
3174 static void TextAction (TexT t)
3175 
3176 {
3177   Int2         i;
3178   FormInfoPtr  pFormInfo;
3179   Char         str [256];
3180 
3181   pFormInfo = (FormInfoPtr) GetObjectExtra (t);
3182 
3183   /* Enable or disable the 'Accept' button based */
3184   /* on the mode and the current text.           */
3185 
3186   if (pFormInfo->currMode == RANGE_MODE) {
3187     if (TextHasNoText (pFormInfo->fromText) &&
3188         TextHasNoText (pFormInfo->toText))
3189       SafeDisable (pFormInfo->acceptButton);
3190     else
3191       SafeEnable (pFormInfo->acceptButton);
3192   } else {
3193     GetTitle (pFormInfo->termText, str, sizeof (str));
3194     if (StringHasNoText (str)) {
3195       if (pFormInfo->currMode == SELECTION_MODE && str [0] == ' ')
3196         SafeEnable (pFormInfo->acceptButton);
3197       else
3198         SafeDisable (pFormInfo->acceptButton);
3199     } else
3200       SafeEnable (pFormInfo->acceptButton);
3201   }
3202 
3203   /* Get the current text */
3204 
3205   GetTitle (t, str, sizeof (str));
3206 
3207   /* If there is no text then clear */
3208   /* the 'Term Selection' window.   */
3209 
3210   if (str [0] == '\0') {
3211     pFormInfo->availItem = 0;
3212     pFormInfo->availRow = 0;
3213     Reset (pFormInfo->availDoc);
3214     for (i = 0; i < 7; i++)
3215       AppendText (pFormInfo->availDoc, " \n", &availParFmt, availColFmt,
3216           systemFont);
3217     InvalDocument (pFormInfo->availDoc);
3218     pFormInfo->textChanged = FALSE;
3219     pFormInfo->okayToAccept = FALSE;
3220     pFormInfo->availCurrentPage = 0;
3221   }
3222 
3223   /* If there is text, then attempt to scroll */
3224   /* to it in the 'Term Selection' window.    */
3225 
3226   else {
3227     pFormInfo->textChanged = TRUE;
3228     pFormInfo->okayToAccept = FALSE;
3229     if (pFormInfo->availCurrentPage > 0 &&
3230     pFormInfo->currMode == SELECTION_MODE)
3231       ScrollToText (pFormInfo, str, pFormInfo->availCurrentPage, TRUE, TRUE);
3232     Update ();
3233   }
3234 }
3235 
3236 /*==================================================================*/
3237 /*                                                                   */
3238 /*  ToTextAction () -                                                */
3239 /*                                                                   */
3240 /*===================================================================*/
3241 
3242 static void ToTextAction (TexT t)
3243 
3244 {
3245   Int2         i;
3246   FormInfoPtr  pFormInfo;
3247   Char         str [256];
3248 
3249   pFormInfo = (FormInfoPtr) GetObjectExtra (t);
3250 
3251   pFormInfo->currRangeField = E2_RANGE_TO;
3252 
3253   if (TextHasNoText (pFormInfo->fromText) &&
3254       TextHasNoText (pFormInfo->toText))
3255     SafeDisable (pFormInfo->acceptButton);
3256   else
3257     SafeEnable (pFormInfo->acceptButton);
3258   
3259   GetTitle (t, str, sizeof (str));
3260   if (str [0] == '\0') {
3261     pFormInfo->availItem = 0;
3262     pFormInfo->availRow = 0;
3263     Reset (pFormInfo->availDoc);
3264     for (i = 0; i < 7; i++)
3265       AppendText (pFormInfo->availDoc, " \n", &availParFmt, availColFmt, systemFont);
3266     InvalDocument (pFormInfo->availDoc);
3267     pFormInfo->isToTextChanged = FALSE;
3268     pFormInfo->isValidTo = FALSE;
3269     pFormInfo->availCurrentPage = 0;
3270   } else {
3271     pFormInfo->isToTextChanged = TRUE;
3272     pFormInfo->isValidTo = TRUE;
3273     if (pFormInfo->availCurrentPage > 0)
3274       ScrollToText (pFormInfo, str, pFormInfo->availCurrentPage, TRUE, TRUE);
3275     Update ();
3276   }
3277 }
3278 
3279 /*==================================================================*/
3280 /*                                                                   */
3281 /*  FromTextAction () -                                              */
3282 /*                                                                   */
3283 /*===================================================================*/
3284 
3285 static void FromTextAction (TexT t)
3286 
3287 {
3288   Int2         i;
3289   FormInfoPtr  pFormInfo;
3290   Char         str [256];
3291 
3292   pFormInfo = (FormInfoPtr) GetObjectExtra (t);
3293 
3294   pFormInfo->currRangeField = E2_RANGE_FROM;
3295 
3296   if (TextHasNoText (pFormInfo->fromText) &&
3297       TextHasNoText (pFormInfo->toText))
3298     SafeDisable (pFormInfo->acceptButton);
3299   else
3300     SafeEnable (pFormInfo->acceptButton);
3301 
3302   GetTitle (t, str, sizeof (str));
3303   if (str [0] == '\0') {
3304     pFormInfo->availItem = 0;
3305     pFormInfo->availRow = 0;
3306     Reset (pFormInfo->availDoc);
3307     for (i = 0; i < 7; i++)
3308       AppendText (pFormInfo->availDoc, " \n", &availParFmt,
3309                   availColFmt, systemFont);
3310     InvalDocument (pFormInfo->availDoc);
3311     pFormInfo->isFromTextChanged = FALSE;
3312     pFormInfo->isValidFrom = FALSE;
3313     pFormInfo->availCurrentPage = 0;
3314   } else {
3315     pFormInfo->isFromTextChanged = TRUE;
3316     pFormInfo->isValidFrom = TRUE;
3317     if (pFormInfo->availCurrentPage > 0)
3318       ScrollToText (pFormInfo, str, pFormInfo->availCurrentPage, TRUE, TRUE);
3319     Update ();
3320   }
3321 }
3322 
3323 /*==================================================================*/
3324 /*                                                                  */
3325 /*  ChangeMode () -                                                 */
3326 /*                                                                  */
3327 /*==================================================================*/
3328 
3329 static void ChangeMode (PopuP p)
3330 
3331 {
3332   AlistDialogPtr     adp;
3333   Char               ch;
3334   Int2               i;
3335   EnumFieldAssocPtr  modeSet;
3336   ModeChoice         menuMode;
3337   ModeChoice         selectedMode;
3338   CharPtr            ptr, text;
3339   FormInfoPtr        pFormInfo;
3340 
3341 
3342   /*------------------------------------------*/
3343   /* Convert the menu choice into a mode type */
3344   /*------------------------------------------*/
3345 
3346   adp = (AlistDialogPtr) GetObjectExtra (p);
3347   pFormInfo = adp->userdata;
3348   modeSet = adp->alist;
3349   menuMode = (ModeChoice) (GetValue (p) - 1);
3350   selectedMode = (ModeChoice) modeSet [menuMode].value;
3351 
3352   pFormInfo->currMode = selectedMode;
3353 
3354   /* handle special modes, populate termlist */
3355   if (selectedMode == TAXONOMY_MODE || selectedMode == MESH_TREE_MODE) {
3356     SafeHide (pFormInfo->termGroup);
3357     SafeHide (pFormInfo->rangeGroup);
3358     text = SaveStringFromText (pFormInfo->termText);
3359     WatchCursor ();
3360     Update ();
3361     if (text != NULL) {
3362       ptr = text;
3363       ch = *ptr;
3364       while (ch != '\0' && ch >= ' ') {
3365         ptr++;
3366         ch = *ptr;
3367       }
3368       *ptr = '\0';
3369       if ((*text == '\0') || (! RepopulateTaxonomy (pFormInfo, text))) {
3370         RepopulateTaxonomyRoot (pFormInfo);
3371       }
3372     } else {
3373       RepopulateTaxonomyRoot (pFormInfo);
3374     }
3375     ArrowCursor ();
3376     MemFree (text);
3377     SafeShow (pFormInfo->taxLineagePopup);
3378     pFormInfo->textChanged = FALSE;
3379     pFormInfo->okayToAccept = TRUE;
3380   } else if (selectedMode == RANGE_MODE) {
3381     SafeHide (pFormInfo->termGroup);
3382     SafeHide (pFormInfo->taxLineagePopup);
3383     SafeShow (pFormInfo->rangeGroup);
3384     TextAction (pFormInfo->fromText);
3385     pFormInfo->availItem = 0;
3386     pFormInfo->availRow = 0;
3387     Reset (pFormInfo->availDoc);
3388     SetDocCache (pFormInfo->availDoc, NULL, NULL, NULL);
3389     for (i = 0; i < 7; i++) {
3390       AppendText (pFormInfo->availDoc, " \n", &availParFmt, availColFmt, systemFont);
3391     }
3392     InvalDocument (pFormInfo->availDoc);
3393     Select (pFormInfo->fromText);
3394   } else {
3395     SafeHide (pFormInfo->rangeGroup);
3396     SafeHide (pFormInfo->taxLineagePopup);
3397     SafeShow (pFormInfo->termGroup);
3398     pFormInfo->availItem = 0;
3399     pFormInfo->availRow = 0;
3400     pFormInfo->availCurrentPage = 0;
3401     TextAction (pFormInfo->termText);
3402     Reset (pFormInfo->availDoc);
3403     SetDocCache (pFormInfo->availDoc, NULL, NULL, NULL);
3404     for (i = 0; i < 7; i++) {
3405       AppendText (pFormInfo->availDoc, " \n", &availParFmt, availColFmt, systemFont);
3406     }
3407     InvalDocument (pFormInfo->availDoc);
3408     Select (pFormInfo->termText);
3409   }
3410 
3411   Update ();
3412 }
3413 
3414 /*==================================================================*/
3415 /*                                                                  */
3416 /*  ChangeMode_Callback () -                                        */
3417 /*                                                                  */
3418 /*==================================================================*/
3419 
3420 static void ChangeMode_Callback (PopuP p)
3421 
3422 {
3423   ChangeMode (p);
3424 }
3425 
3426 /*==================================================================*/
3427 /*                                                                  */
3428 /*  ChangeField () - Sets the current field to the one selected in  */
3429 /*                  the given PopuP object, then selects the        */
3430 /*                  corresponding modes PopuP that contains the     */
3431 /*                  possible modes for this field.                  */
3432 /*                                                                  */
3433 /*==================================================================*/
3434 
3435 static void ChangeField (PopuP p)
3436 
3437 {
3438   AlistDialogPtr     adp;
3439   EnumFieldAssocPtr  fieldAList;
3440   Int2               fieldId;
3441   ModeIndex          md, mode;
3442   Int2               menuChoice;
3443   FormInfoPtr        pFormInfo;
3444 
3445   /*------------------------*/
3446   /* Get the selected field */
3447   /*------------------------*/
3448 
3449   adp = (AlistDialogPtr) GetObjectExtra (p);
3450   pFormInfo = adp->userdata;
3451   fieldAList = adp->alist;
3452 
3453   menuChoice = GetValue (p) - 1;
3454   if (menuChoice < 0) return;
3455 
3456   fieldId = fieldAList [menuChoice].value;
3457 
3458   /*--------------------------------*/
3459   /* Select and make active the set */
3460   /* of modes for this field.       */
3461   /*--------------------------------*/
3462 
3463   mode = (ModeIndex) FieldGetModePopup (pFormInfo->currDb, fieldId, fieldAList, pFormInfo);
3464   if (mode < 0) return;
3465 
3466   for (md = POPUP_MULT; md <= POPUP_UID; md++)
3467     if (md != mode)
3468       SafeHide (pFormInfo->modesPopup [md]);
3469 
3470   SafeShow (pFormInfo->modesPopup [mode]);
3471   ChangeMode (pFormInfo->modesPopup [mode]);
3472 }
3473 
3474 /*==================================================================*/
3475 /*                                                                  */
3476 /*  ChangeField_Callback () -                                       */
3477 /*                                                                  */
3478 /*==================================================================*/
3479 
3480 static void ChangeField_Callback (PopuP p)
3481 
3482 {
3483   ChangeField (p);
3484 }
3485 
3486 /*==================================================================*/
3487 /*                                                                  */
3488 /*  ChangeDatabase () -                                             */
3489 /*                                                                  */
3490 /*==================================================================*/
3491 
3492 static void ChangeDatabase (PopuP p)
3493 
3494 {
3495   FormInfoPtr     pFormInfo;
3496   Int2            db;
3497   Int2            dbase;
3498   UIEnum          val;
3499   Entrez2InfoPtr  e2ip;
3500 
3501   pFormInfo = (FormInfoPtr) GetObjectExtra (p);
3502   if (pFormInfo == NULL || pFormInfo->fieldsPopup == NULL) return;
3503 
3504   e2ip = Query_GetInfo ();
3505 
3506   val = GetValue (p) - 1;
3507 
3508   for (db = 0; db < e2ip->db_count; db++) {
3509     if (db != (Int2) val) {
3510       SafeHide (pFormInfo->fieldsPopup [db]);
3511     }
3512   }
3513 
3514   dbase = (Int2) val;
3515   pFormInfo->currDb = dbase;
3516   SafeShow (pFormInfo->fieldsPopup [dbase]);
3517   ChangeField (pFormInfo->fieldsPopup [dbase]);
3518 
3519   DoResetAvail (pFormInfo, FALSE);
3520   ResetChosen (pFormInfo);
3521 
3522   if (pFormInfo->currMode == TAXONOMY_MODE || pFormInfo->currMode == MESH_TREE_MODE) {
3523     SafeHide (pFormInfo->termGroup);
3524     SafeHide (pFormInfo->rangeGroup);
3525     SafeShow (pFormInfo->taxLineagePopup);
3526   } else if (pFormInfo->currMode == RANGE_MODE) {
3527     SafeHide (pFormInfo->termGroup);
3528     SafeHide (pFormInfo->taxLineagePopup);
3529     SafeShow (pFormInfo->rangeGroup);
3530     Select (pFormInfo->fromText);
3531   } else {
3532     SafeHide (pFormInfo->rangeGroup);
3533     SafeHide (pFormInfo->taxLineagePopup);
3534     SafeShow (pFormInfo->termGroup);
3535     Select (pFormInfo->termText);
3536   }
3537 
3538   Reset (pFormInfo->advQueryText);
3539 }
3540 
3541 /*==================================================================*/
3542 /*                                                                  */
3543 /*  ChangeDatabase_Callback () -                                    */
3544 /*                                                                  */
3545 /*==================================================================*/
3546 
3547 static void ChangeDatabase_Callback (PopuP p)
3548 
3549 {
3550   ChangeDatabase (p);
3551 }
3552 
3553 /*==================================================================*/
3554 /*                                                                  */
3555 /*  EditMessage_Callback () -                                       */
3556 /*                                                                  */
3557 /*==================================================================*/
3558 
3559 static void EditMessage_Callback (ForM f, Int2 mssg)
3560 
3561 {
3562   FormInfoPtr  pFormInfo;
3563 
3564   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
3565 
3566   switch (mssg) {
3567     case VIB_MSG_CUT:
3568       StdCutTextProc (NULL);
3569       break;
3570     case VIB_MSG_COPY:
3571       StdCopyTextProc (NULL);
3572       break;
3573     case VIB_MSG_PASTE:
3574       StdPasteTextProc (NULL);
3575       break;
3576     case VIB_MSG_DELETE:
3577       StdDeleteTextProc (NULL);
3578       break;
3579     default:
3580       if (pFormInfo->appmessage != NULL) {
3581         pFormInfo->appmessage (f, mssg);
3582       }
3583       break;
3584   }
3585 }
3586 
3587 /*==================================================================*/
3588 /*                                                                  */
3589 /*  TermListActivate_Callback () -                                  */
3590 /*                                                                  */
3591 /*==================================================================*/
3592 
3593 static void TermListActivate_Callback (WindoW w)
3594 
3595 {
3596   FormInfoPtr  pFormInfo;
3597 
3598   pFormInfo = (FormInfoPtr) GetObjectExtra (w);
3599 
3600   if (pFormInfo->activate != NULL)
3601     pFormInfo->activate (w);
3602 }
3603 
3604 /*==================================================================*/
3605 /*                                                                  */
3606 /*  TermListCleanup_Callback () -                                   */
3607 /*                                                                  */
3608 /*==================================================================*/
3609 
3610 static void TermListCleanup_Callback (GraphiC g, VoidPtr data)
3611 
3612 {
3613   FormInfoPtr  pFormInfo;
3614 
3615   pFormInfo = (FormInfoPtr) GetObjectExtra (g);
3616 
3617   MemFree (pFormInfo->fieldsPopup);
3618   StdCleanupFormProc (g, data);
3619 }
3620 
3621 /*==================================================================*/
3622 /*                                                                  */
3623 /*  Quit_Callback () -                                              */
3624 /*                                                                  */
3625 /*==================================================================*/
3626 
3627 static void Quit_Callback (IteM i)
3628 
3629 {
3630   QuitProgram ();
3631 }
3632 
3633 /*==================================================================*/
3634 /*                                                                  */
3635 /*  StripNewLine () - Strip the newline character from the end of   */
3636 /*                   a string.                                      */
3637 /*                                                                  */
3638 /*==================================================================*/
3639 
3640 static void StripNewLine (CharPtr str)
3641 
3642 {
3643   CharPtr  chptr;
3644 
3645   if (StringHasNoText (str))
3646     return;
3647   chptr = StringRChr (str, '\n');
3648   if (chptr != NULL) {
3649     *chptr = '\0';
3650   }
3651   chptr = StringRChr (str, '\r');
3652   if (chptr != NULL) {
3653     *chptr = '\0';
3654   }
3655 }
3656 
3657 /*==================================================================*/
3658 /*                                                                  */
3659 /*  Query_AddUidsTerm () -                                          */
3660 /*                                                                  */
3661 /*==================================================================*/
3662 
3663 static Boolean Query_AddUidsTerm (ForM f, CharPtr uidListName, Int4 iUidCount, Int4Ptr uids, Int2 db)
3664 
3665 {
3666   CharPtr            dbName;
3667   Entrez2RequestPtr  e2rq;
3668   Entrez2ReplyPtr    e2ry;
3669   StateDataPtr       sdp;
3670   StateDataPtr       prev;
3671   Char               displayStr [256];
3672   RecT               r;
3673   BaR                sb;
3674   FormInfoPtr        pFormInfo;
3675   Boolean            doNotTranslate;
3676 
3677   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
3678 
3679   /*-----------------------------------------*/
3680   /* Make sure we don't add a Uid list twice */
3681   /*-----------------------------------------*/
3682 
3683   for (sdp = pFormInfo->termList; sdp != NULL; sdp = sdp->next)
3684     if (MeshStringICmp (sdp->term, uidListName) == 0) return FALSE;
3685 
3686   /*--------------------------------*/
3687   /* Create a term for the UID list */
3688   /*--------------------------------*/
3689 
3690   sdp = StateDataNew (pFormInfo);
3691   if (pFormInfo->termList == NULL)
3692     pFormInfo->termList = sdp;
3693 
3694   if (sdp == NULL) return FALSE;
3695 
3696   (pFormInfo->chosenNumLines)++;
3697 
3698   sdp->field = StringSave ("----");
3699   /* sdp->term = StringSave (uidListName); */
3700   sdp->count = iUidCount;
3701   /* sdp->uids = uids; */
3702   sdp->group = GROUP_SINGLE;
3703   sdp->above = ENTREZ_OP_NONE;
3704 
3705   dbName = DBGetNameFromID (pFormInfo->currDb);
3706   e2rq = EntrezCreateBooleanRequest (FALSE, FALSE, dbName, NULL, 0, 0, NULL, 0, 0);
3707   if (e2rq == NULL) return FALSE;
3708 
3709   doNotTranslate = FALSE;
3710   EntrezAddToBooleanRequest (e2rq, NULL, 0, NULL, NULL, NULL, 0, iUidCount, uids, NULL, FALSE, doNotTranslate);
3711   EntrezSetUseHistoryFlag (e2rq);
3712 
3713   if (ShowASN () == TRUE)
3714     DisplayEntrezRequest (e2rq);
3715 
3716   e2ry = SpecialEntrezSynchronousQuery (e2rq);
3717   if (e2ry == NULL) return FALSE;
3718 
3719   if (ShowASN () == TRUE)
3720     DisplayEntrezReply (e2ry);
3721 
3722   e2rq = Entrez2RequestFree (e2rq);
3723   sdp->key = StringSave (e2ry->key);
3724   sdp->term = StringSave (e2ry->key);
3725   Entrez2ReplyFree (e2ry);
3726 
3727   /*-------------------------------------*/
3728   /* Add the term to the current Query's */
3729   /* linked list of terms.               */
3730   /*-------------------------------------*/
3731 
3732   prev = sdp->prev;
3733   if (prev != NULL) {
3734     sdp->above = ENTREZ_OP_AND;
3735     prev->below = ENTREZ_OP_AND;
3736   }
3737   sdp->below = ENTREZ_OP_NONE;
3738   sdp->state = STATE_ON;
3739 
3740   /*---------------------------------------------*/
3741   /* Add the term to the query refinement window */
3742   /*---------------------------------------------*/
3743 
3744   sprintf (displayStr, "%s\t [%s]\t%ld\n", sdp->term, sdp->field, (long) iUidCount);
3745   AppendText (pFormInfo->chosenDoc, displayStr, &chosenParFmt, chosenColFmt, systemFont);
3746 
3747   /*---------------------------------*/
3748   /* Display our new query string in */
3749   /* Query Refinement window.        */
3750   /*---------------------------------*/
3751 
3752   InvalDocRows (pFormInfo->chosenDoc, pFormInfo->chosenNumLines, 1, 1);
3753   AdjustDocScroll (pFormInfo->chosenDoc);
3754   sb = GetSlateVScrollBar ((SlatE) pFormInfo->chosenDoc);
3755   ResetClip ();
3756   SetBarValue (sb, MAX (pFormInfo->chosenNumLines - 7, 0));
3757   ObjectRect (pFormInfo->chosenDoc, &r);
3758   InsetRect (&r, 4, 4);
3759   r.right = r.left + 16;
3760   InsetRect (&r, -1, -1);
3761   Select (pFormInfo->chosenDoc);
3762   InvalRect (&r);
3763 
3764   Update ();
3765 
3766   return TRUE;
3767 }
3768 
3769 /*==================================================================*/
3770 /*                                                                  */
3771 /*  ImportUIDs_Callback () -                                        */
3772 /*                                                                  */
3773 /*==================================================================*/
3774 
3775 static void ImportUIDs_Callback (IteM i)
3776 
3777 {
3778   Entrez2InfoPtr    e2ip;
3779   Entrez2DbInfoPtr  e2dbInfo;
3780   FILE              *fp;
3781   FormInfoPtr       pFormInfo;
3782   ByteStorePtr      bsp;
3783   Int4              iUidCount;
3784   Char              fullName [PATH_MAX];
3785   CharPtr           baseName;
3786   Char              str [32];
3787   Int4              uid;
3788   Int4Ptr           uids = NULL;
3789   WindoW            w;
3790 
3791   /*----------------------------*/
3792   /* Get the Term Form info for */
3793   /* the parent window.         */
3794   /*----------------------------*/
3795 
3796 #ifdef WIN_MAC
3797   w = FrontWindow ();
3798 #else
3799   w = ParentWindow (i);
3800 #endif
3801 
3802   pFormInfo = (FormInfoPtr) GetObjectExtra (w);
3803 
3804   /*------------------------------*/
3805   /* Get the name of the UID file */
3806   /* and then open it.            */
3807   /*------------------------------*/
3808 
3809   if (! GetInputFileName (fullName, sizeof (fullName), "", "TEXT")) return;
3810 
3811   fp = FileOpen (fullName, "r");
3812   if (fp == NULL) return;
3813 
3814   /*-------------------------------*/
3815   /* Create a ByteStore Pointer to */
3816   /* store the UIDs in.            */
3817   /*-------------------------------*/
3818 
3819   bsp = BSNew (128);
3820   if (bsp == NULL) {
3821     FileClose (fp);
3822     return;
3823   }
3824 
3825   /*-------------------------------------*/
3826   /* Read the first line of the file and */
3827   /* verify that it contains a valid     */
3828   /* database name.                      */
3829   /*                                     */
3830   /* NOTE - Special case for medline     */
3831   /*        needs to me removed once     */
3832   /*        it is fixed on the server.   */
3833   /*                                     */
3834   /*-------------------------------------*/
3835 
3836   if (!FileGets (str, sizeof (str), fp)) {
3837     BSFree (bsp);
3838     FileClose (fp);
3839     return;
3840   }
3841 
3842   StripNewLine (str);
3843 
3844   e2ip = Query_GetInfo ();
3845 
3846   for (e2dbInfo = e2ip->db_info; e2dbInfo != NULL; e2dbInfo = e2dbInfo->next)
3847     if (StringICmp (e2dbInfo->db_menu, &str [1]) == 0) break;
3848 
3849   if (e2dbInfo == NULL) {
3850     Message (MSG_POSTERR, "First line must be in the form >DbName");
3851     BSFree (bsp);
3852     FileClose (fp);
3853     return;
3854   }
3855 
3856   /*-----------------------------------*/
3857   /* Read the rest of the lines in and */
3858   /* add each UID to the byteStore.    */
3859   /*-----------------------------------*/
3860 
3861   while (FileGets (str, sizeof (str), fp)) {
3862     StripNewLine (str);
3863     if (str [0] != '\0' && StrToLong (str, &uid))
3864       BSWrite (bsp, &uid, sizeof (DocUid));
3865   }
3866 
3867   BSSeek (bsp, 0L, 0);
3868   iUidCount = (Int4) ((BSLen (bsp)) / sizeof (Int4));
3869   uids = (Int4Ptr) BSMerge (bsp, NULL);
3870 
3871   /*--------------------------------*/
3872   /* Add the list of UIDs as a term */
3873   /* in the current query.          */
3874   /*--------------------------------*/
3875 
3876   baseName = FileNameFind (fullName);
3877   Query_AddUidsTerm (pFormInfo->form, baseName, iUidCount, uids, pFormInfo->currDb);
3878   Select (pFormInfo->termText);
3879 
3880   /*---------------------------*/
3881   /* Get a count of terms that */
3882   /* satisfy this query.       */
3883   /*---------------------------*/
3884 
3885   Update ();
3886   RecalculateChosen (pFormInfo);
3887   ArrowCursor ();
3888   Update ();
3889 
3890   /*----------------------------------*/
3891   /* Clean up and return successfully */
3892   /*----------------------------------*/
3893 
3894   BSFree (bsp);
3895   MemFree (uids);
3896   FileClose (fp);
3897 }
3898 
3899 /*==================================================================*/
3900 /*                                                                  */
3901 /*  ExportUIDs_Callback () -                                        */
3902 /*                                                                  */
3903 /*==================================================================*/
3904 
3905 static void ExportUIDs_Callback (IteM i)
3906 
3907 {
3908   CharPtr                 dbName;
3909   Entrez2BooleanReplyPtr  e2BooleanPtr;
3910   Entrez2IdListPtr        e2UidList;
3911   FILE                    *fp;
3912   FormInfoPtr             pFormInfo;
3913   Char                    path [PATH_MAX];
3914   Char                    headerStr [32];
3915   Int4Ptr                 uids;
3916   Int4                    uidNum;
3917   Char                    uidStr [32];
3918   WindoW                  w;
3919 
3920   /*----------------------------*/
3921   /* Get the Term Form info for */
3922   /* the parent window.         */
3923   /*----------------------------*/
3924 
3925 #ifdef WIN_MAC
3926   w = FrontWindow ();
3927 #else
3928   w = ParentWindow (i);
3929 #endif
3930 
3931   pFormInfo = (FormInfoPtr) GetObjectExtra (w);
3932 
3933   /*-------------------------------*/
3934   /* Get a file name from the user */
3935   /* and open that file.           */
3936   /*-------------------------------*/
3937 
3938   if (! GetOutputFileName (path, sizeof (path), NULL)) return;
3939 
3940 #ifdef WIN_MAC
3941   FileCreate (path, "TEXT", "ttxt");
3942 #endif
3943 
3944   fp = FileOpen (path, "w");
3945   if (fp == NULL) return;
3946 
3947   WatchCursor ();
3948 
3949   /*-----------------------------------*/
3950   /* Write the header line to the file */
3951   /*-----------------------------------*/
3952 
3953   dbName = DBGetNameFromID (pFormInfo->currDb);
3954   sprintf (headerStr, ">%s\n", dbName);
3955   FilePuts (headerStr, fp);
3956 
3957   /*-----------------------*/
3958   /* Create a list of UIDS */
3959   /*-----------------------*/
3960 
3961   e2BooleanPtr = Query_FetchUIDs (pFormInfo->form);
3962   e2UidList = e2BooleanPtr->uids;
3963 
3964   uids = (Int4Ptr) BSMerge (e2UidList->uids, NULL);
3965 
3966   /*----------------------------*/
3967   /* Write the uids to the file */
3968   /*----------------------------*/
3969 
3970   for (uidNum = 0; uidNum < e2UidList->num; uidNum++) {
3971     sprintf (uidStr, "%ld\n", (long) uids [uidNum]);
3972     FilePuts (uidStr, fp);
3973   }
3974 
3975   /*----------------------------------*/
3976   /* Clean up and return successfully */
3977   /*----------------------------------*/
3978 
3979   FileClose (fp);
3980   free (uids);
3981   ArrowCursor ();
3982   Entrez2BooleanReplyFree (e2BooleanPtr);
3983 }
3984 
3985 /*==================================================================*/
3986 /*                                                                  */
3987 /*  AdvQueryInit () - Initialize the lexical static variables for   */
3988 /*                     parsing a new string.                        */
3989 /*                                                                  */
3990 /*==================================================================*/
3991 
3992 static Int2 AdvQueryInit (FormInfoPtr pFormInfo, CharPtr newStr)
3993 
3994 {
3995   /*-----------------*/
3996   /* Check parameter */
3997   /*-----------------*/
3998 
3999   if (newStr == NULL) return -1;
4000 
4001   /*-----------------------------------------*/
4002   /* Initialize the lexical static variables */
4003   /* using the new string.                   */
4004   /*-----------------------------------------*/
4005 
4006   MemFree (pFormInfo->advQueryLexStr);
4007   pFormInfo->advQueryLexStr = StringSave (newStr);
4008   pFormInfo->advQueryLexPos = 0;
4009   pFormInfo->advQueryLexState = LEXSTATE_IDLE;
4010 
4011   /*-------------------------------------*/
4012   /* Free the linked list of query terms */
4013   /* so that we can build a new one with */
4014   /* the given string.                   */
4015   /*-------------------------------------*/
4016 
4017   ResetChosen (pFormInfo);
4018 
4019   /*---------------------*/
4020   /* Return successfully */
4021   /*---------------------*/
4022 
4023   return 0;
4024 }
4025 
4026 /*==================================================================*/
4027 /*                                                                  */
4028 /*  LexClassifyChar () -                                            */
4029 /*                                                                  */
4030 /*     NOTE -- Taken from LexClassifyChar() in accutils.c           */
4031 /*                                                                  */
4032 /*==================================================================*/
4033 
4034 static Int2 LexClassifyChar (Char c)
4035 
4036 {
4037   Int2  retval;
4038 
4039   switch (c) {
4040     case '(':
4041       retval = LEXCHAR_LPAREN;
4042       break;
4043     case ')':
4044       retval = LEXCHAR_RPAREN;
4045       break;
4046     case '[':
4047       retval = LEXCHAR_LBRACKET;
4048       break;
4049     case ']':
4050       retval = LEXCHAR_RBRACKET;
4051       break;
4052     case '"':
4053       retval = LEXCHAR_QUOTE;
4054       break;
4055     case '&':
4056       retval = LEXCHAR_AND;
4057       break;
4058     case '|':
4059       retval = LEXCHAR_OR;
4060       break;
4061     case '-':
4062       retval = LEXCHAR_NOT;
4063       break;
4064     case ',':
4065       retval = LEXCHAR_COMMA;
4066       break;
4067     case '@':
4068       retval = LEXCHAR_ATSIGN;
4069       break;
4070     case '\\':
4071       retval = LEXCHAR_BACKSLASH;
4072       break;
4073     case ' ':
4074     case '\t':
4075       retval = LEXCHAR_WHITESPACE;
4076       break;
4077     case ';':
4078       retval = LEXCHAR_SEMICOLON;
4079       break;
4080     case ':':
4081       retval = LEXCHAR_COLON;
4082       break;
4083     case '\0':
4084       retval = LEXCHAR_NULL;
4085       break;
4086     case '\r':
4087     case '\n':
4088       retval = LEXCHAR_EOL;
4089       break;
4090     default:
4091       retval = LEXCHAR_OTHER;
4092       break;
4093   }
4094 
4095   return retval;
4096 }
4097 
4098 /*==================================================================*/
4099 /*                                                                  */
4100 /*  AdvQueryGetNextToken() -                                        */
4101 /*                                                                  */
4102 /*        Returns:                                                  */
4103 /*                                                                  */
4104 /*            StartPos - >0 : The position in the static string     */
4105 /*                            pFormInfo->advQueryLexStr where the   */
4106 /*                            token starts.                         */
4107 /*                                                                  */
4108 /*                       -1 : No token found.                       */
4109 /*                                                                  */
4110 /*        Sets:                                                     */
4111 /*                                                                  */
4112 /*            pFormInfo->advQueryNextToken : Contains an            */
4113 /*                            identifier specifying the type of     */
4114 /*                            the token, and if the token is a      */
4115 /*                            string also contains a pointer to     */
4116 /*                            the string.                           */
4117 /*                                                                  */
4118 /*                            Set to NULL if no token found.        */
4119 /*                                                                  */
4120 /*==================================================================*/
4121 
4122 static Int2 AdvQueryGetNextToken (FormInfoPtr pFormInfo)
4123 
4124 {
4125   Int2            startPos;
4126   Int2            classChar;
4127   Int2            token = 0;
4128   Boolean         done;
4129   Char            c;
4130   CharPtr         lexToken = NULL;
4131   CharPtr         lexTokenStart;
4132   Int2            len;
4133   Int2            pos;
4134 
4135   /*------------------*/
4136   /* Check conditions */
4137   /*------------------*/
4138 
4139   if (pFormInfo->advQueryLexStr == NULL) {
4140     pFormInfo->advQueryNextToken = NULL;
4141     return -1;
4142   }
4143 
4144   pFormInfo->advQueryNextToken = &pFormInfo->advQueryNextRealNode;
4145 
4146   /*--------------------------------------*/
4147   /* Find the beginning of the next token */
4148   /* and malloc space for it.             */
4149   /*--------------------------------------*/
4150 
4151   len = StringLen (pFormInfo->advQueryLexStr);
4152   startPos = pFormInfo->advQueryLexPos;
4153 
4154   if (pFormInfo->advQueryLexPos >= len) {
4155     pFormInfo->advQueryLexState = LEXSTATE_ERROR;
4156     token = -1;
4157     lexToken = MemNew (1);
4158   } else {
4159     pos = pFormInfo->advQueryLexPos;
4160     lexToken = MemNew (StringLen (&pFormInfo->advQueryLexStr [pos]) + 1);
4161   }
4162 
4163   lexTokenStart = lexToken;
4164 
4165   /*------------------*/
4166   /*------------------*/
4167 
4168   for (done = FALSE; !done && pFormInfo->advQueryLexPos <= len; pFormInfo->advQueryLexPos++) {
4169     c = pFormInfo->advQueryLexStr [pFormInfo->advQueryLexPos];
4170     classChar = LexClassifyChar (c);
4171     switch (pFormInfo->advQueryLexState) {
4172       case LEXSTATE_IDLE:
4173         switch (classChar) {
4174           case LEXCHAR_LPAREN:
4175             token = LEXTOK_LPAREN;
4176             done = TRUE;
4177             break;
4178           case LEXCHAR_RPAREN:
4179             token = LEXTOK_RPAREN;
4180             done = TRUE;
4181             break;
4182           case LEXCHAR_LBRACKET:
4183             token = LEXTOK_LBRACKET;
4184             done = TRUE;
4185             break;
4186           case LEXCHAR_RBRACKET:
4187             token = LEXTOK_RBRACKET;
4188             done = TRUE;
4189             break;
4190           case LEXCHAR_AND:
4191             token = LEXTOK_AND;
4192             done = TRUE;
4193             break;
4194           case LEXCHAR_OR:
4195             token = LEXTOK_OR;
4196             done = TRUE;
4197             break;
4198           case LEXCHAR_NOT:
4199             token = LEXTOK_NOT;
4200             done = TRUE;
4201             break;
4202           case LEXCHAR_COMMA:
4203             token = LEXTOK_COMMA;
4204             done = TRUE;
4205             break;
4206           case LEXCHAR_ATSIGN:
4207             token = LEXTOK_ATSIGN;
4208             done = TRUE;
4209             break;
4210           case LEXCHAR_COLON:
4211             token = LEXTOK_RANGE;
4212             done = TRUE;
4213             break;
4214           case LEXCHAR_QUOTE:
4215             pFormInfo->advQueryLexState = LEXSTATE_INQUOTE;
4216             break;
4217           case LEXCHAR_BACKSLASH:
4218             pFormInfo->advQueryLexState = LEXSTATE_BACKSLASHED;
4219             break;
4220           case LEXCHAR_EOL:
4221           case LEXCHAR_WHITESPACE:
4222             startPos = pFormInfo->advQueryLexPos + 1;
4223             break;
4224           case LEXCHAR_SEMICOLON:
4225           case LEXCHAR_NULL:
4226             pFormInfo->advQueryLexState = LEXSTATE_ERROR;
4227             done = TRUE;
4228             break;
4229           case LEXCHAR_OTHER:
4230           default:
4231             pFormInfo->advQueryLexState = LEXSTATE_INSTRING;
4232             *lexToken++ = c;
4233             break;
4234         }
4235         break;
4236       case LEXSTATE_BACKSLASHED:
4237         switch (classChar) {
4238           case LEXCHAR_NULL:
4239           case LEXCHAR_EOL:
4240             *lexToken++ = '\0';
4241             done = TRUE;
4242             pFormInfo->advQueryLexState = LEXSTATE_IDLE;
4243             break;
4244           case LEXCHAR_LPAREN:
4245           case LEXCHAR_RPAREN:
4246           case LEXCHAR_LBRACKET:
4247           case LEXCHAR_RBRACKET:
4248           case LEXCHAR_QUOTE:
4249           case LEXCHAR_AND:
4250           case LEXCHAR_OR:
4251           case LEXCHAR_NOT:
4252           case LEXCHAR_COMMA:
4253           case LEXCHAR_ATSIGN:
4254           case LEXCHAR_BACKSLASH:
4255           case LEXCHAR_WHITESPACE:
4256           case LEXCHAR_SEMICOLON:
4257           case LEXCHAR_COLON:
4258           case LEXCHAR_OTHER:
4259           default:
4260             pFormInfo->advQueryLexState = LEXSTATE_INSTRING;
4261             *lexToken++ = c;
4262             break;
4263         }
4264         break;
4265       case LEXSTATE_INQUOTE:
4266         switch (classChar) {
4267           case LEXCHAR_QUOTE:
4268             token = LEXTOK_STRING;
4269             *lexToken++ = '\0';
4270             done = TRUE;
4271             pFormInfo->advQueryLexState = LEXSTATE_IDLE;
4272             break;
4273           case LEXCHAR_BACKSLASH:
4274             pFormInfo->advQueryLexState = LEXSTATE_INQUOTE_AFTERBSLASH;
4275             break;
4276           case LEXCHAR_NULL:
4277           case LEXCHAR_EOL:
4278             pFormInfo->advQueryLexState = LEXSTATE_ERROR;
4279             done = TRUE;
4280             break;
4281           default:
4282             *lexToken++ = c;
4283             break;
4284         }
4285         break;
4286       case LEXSTATE_INQUOTE_AFTERBSLASH:
4287         switch (classChar) {
4288           case LEXCHAR_NULL:
4289           case LEXCHAR_EOL:
4290             pFormInfo->advQueryLexState = LEXSTATE_ERROR;
4291             done = TRUE;
4292             break;
4293           default:
4294             pFormInfo->advQueryLexState = LEXSTATE_INQUOTE;
4295             *lexToken++ = c;
4296             break;
4297         }
4298         break;
4299       case LEXSTATE_INSTRING:
4300         switch (classChar) {
4301           case LEXCHAR_WHITESPACE:
4302           case LEXCHAR_SEMICOLON:
4303           case LEXCHAR_NULL:
4304           case LEXCHAR_EOL:
4305             token = LEXTOK_STRING;
4306             *lexToken++ = '\0';
4307             done = TRUE;
4308             pFormInfo->advQueryLexState = LEXSTATE_IDLE;
4309             break;
4310           case LEXCHAR_BACKSLASH:
4311             pFormInfo->advQueryLexState = LEXSTATE_BACKSLASHED;
4312             break;
4313           case LEXCHAR_QUOTE:
4314             pFormInfo->advQueryLexState = LEXSTATE_INQUOTE;
4315             break;
4316           case LEXCHAR_OTHER:
4317             *lexToken++ = c;
4318             break;
4319           default:
4320             token = LEXTOK_STRING;
4321             *lexToken++ = '\0';
4322             done = TRUE;
4323             pFormInfo->advQueryLexState = LEXSTATE_IDLE;
4324             pFormInfo->advQueryLexPos--;        /* push back last character */
4325             break;
4326         }
4327         break;
4328       case LEXSTATE_ERROR:
4329         done = TRUE;
4330         break;
4331     }
4332   }
4333 
4334   pFormInfo->advQueryNextToken->choice = (Uint1) token;
4335   pFormInfo->advQueryNextToken->data.ptrvalue = NULL;
4336 
4337   if (token == LEXTOK_STRING)
4338     pFormInfo->advQueryNextToken->data.ptrvalue = lexTokenStart;
4339   else
4340     MemFree (lexTokenStart);
4341 
4342   if (pFormInfo->advQueryLexState == LEXSTATE_ERROR) {
4343     pFormInfo->advQueryNextToken = NULL;
4344     return -1;
4345   } else
4346     return startPos;
4347 }
4348 
4349 /*===================================================================*/
4350 /*                                                                   */
4351 /*  CloseGroup () -                                                  */
4352 /*                                                                   */
4353 /*===================================================================*/
4354 
4355 static Boolean CloseGroup (FormInfoPtr pFormInfo)
4356 
4357 {
4358   StateDataPtr  pLastTerm;
4359 
4360   /*--------------*/
4361   /* Sanity check */
4362   /*--------------*/
4363 
4364   if (pFormInfo == NULL || pFormInfo->termList == NULL) return FALSE;
4365 
4366   /*--------------------------------*/
4367   /* Find the last term in the list */
4368   /*--------------------------------*/
4369 
4370   pLastTerm = pFormInfo->termList;
4371   while (pLastTerm->next != NULL)
4372     pLastTerm = pLastTerm->next;
4373 
4374   /*----------------------*/
4375   /* Set its group status */
4376   /*----------------------*/
4377 
4378   switch (pLastTerm->group) {
4379     case GROUP_SINGLE:
4380     case GROUP_LAST:
4381       break;
4382     case GROUP_FIRST:
4383       pLastTerm->group = GROUP_SINGLE;
4384       break;
4385     case GROUP_MIDDLE:
4386       pLastTerm->group = GROUP_LAST;
4387       break;
4388     default:
4389       break;
4390   }
4391 
4392   /*---------------------*/
4393   /* Return successfully */
4394   /*---------------------*/
4395 
4396   return TRUE;
4397 }
4398 
4399 /*===================================================================*/
4400 /*                                                                   */
4401 /*  ParseANDedTerms () -                                             */
4402 /*                                                                   */
4403 /*     NOTE -- Brought over from accutils.c                          */
4404 /*                                                                   */
4405 /*===================================================================*/
4406 
4407 /* prototype for recursive function */
4408 
4409 static Boolean ParseTermList (FormInfoPtr pFormInfo, Int2 db, Int2 fld, Int2 currOp);
4410 
4411 static Boolean ParseANDedTerms (FormInfoPtr pFormInfo, Int2 db, Int2 fld, Int2 currOp)
4412 
4413 {
4414   if (! ParseTermList (pFormInfo, db, fld, currOp)) return FALSE;
4415 
4416   while (pFormInfo->advQueryNextToken != NULL && pFormInfo->advQueryNextToken->choice == LEXTOK_AND) {
4417     AdvQueryGetNextToken (pFormInfo);
4418     if (! ParseTermList (pFormInfo, db, fld, LEXCHAR_AND)) return FALSE;
4419   }
4420 
4421   return TRUE;
4422 }
4423 
4424 /*===================================================================*/
4425 /*                                                                   */
4426 /*  ParseORedTerms () -                                              */
4427 /*                                                                   */
4428 /*     NOTE -- Brought over from accutils.c                          */
4429 /*                                                                   */
4430 /*===================================================================*/
4431 
4432 static Boolean ParseORedTerms (FormInfoPtr pFormInfo, Int2 db, Int2 fld, Int2 currOp)
4433 
4434 {
4435   if (! ParseANDedTerms (pFormInfo, db, fld, currOp)) return FALSE;
4436 
4437   while (pFormInfo->advQueryNextToken != NULL && pFormInfo->advQueryNextToken->choice == LEXTOK_OR) {
4438     AdvQueryGetNextToken (pFormInfo);
4439     if (! ParseANDedTerms (pFormInfo, db, fld, LEXCHAR_OR)) return FALSE;
4440   }
4441 
4442   return TRUE;
4443 }
4444 
4445 /*===================================================================*/
4446 /*                                                                   */
4447 /*  ParseNOTedTerms () -                                             */
4448 /*                                                                   */
4449 /*     NOTE -- This function brought over from accutils.c            */
4450 /*                                                                   */
4451 /*===================================================================*/
4452 
4453 static Boolean ParseNOTedTerms (FormInfoPtr pFormInfo, Int2 db, Int2 fld, Int2 currOp)
4454 
4455 {
4456   if (! ParseORedTerms (pFormInfo, db, fld, currOp)) return FALSE;
4457 
4458   while ((pFormInfo->advQueryNextToken != NULL) && (pFormInfo->advQueryNextToken->choice == LEXTOK_NOT)) {
4459     AdvQueryGetNextToken (pFormInfo);
4460     if (! ParseORedTerms (pFormInfo, db, fld, LEXCHAR_NOT)) return FALSE;
4461   }
4462 
4463   return TRUE;
4464 }
4465 
4466 /*===================================================================*/
4467 /*                                                                   */
4468 /*  ParseTermList () -                                               */
4469 /*                                                                   */
4470 /*===================================================================*/
4471 
4472 static Boolean ParseTermList (FormInfoPtr pFormInfo, Int2 db, Int2 fld, Int2 currOp)
4473 
4474 {
4475   CharPtr       term;
4476   CharPtr       fldStr;
4477   CharPtr       highRangeStr = NULL;
4478   StateDataPtr  newTermPtr;
4479   Int2          nOperator;
4480 
4481   /*---------------------------------------------*/
4482   /* Check for proper conditions to run function */
4483   /*---------------------------------------------*/
4484 
4485   if (pFormInfo->advQueryNextToken == NULL) {
4486     ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "Null factor");
4487     return FALSE;
4488   }
4489 
4490   /*------------------------------------------*/
4491   /* If we have a left paren, then recursivly */
4492   /* parse what follows it as a term list.    */
4493   /*------------------------------------------*/
4494 
4495   if (pFormInfo->advQueryNextToken->choice == LEXTOK_LPAREN) {
4496     pFormInfo->advQueryNewGroup = TRUE;
4497     AdvQueryGetNextToken (pFormInfo);
4498     if (! ParseNOTedTerms (pFormInfo, db, fld, currOp))
4499       return FALSE;
4500 
4501       /*---------------------------*/
4502     /* If we have a right paren, */
4503     /* close out group.          */
4504       /*---------------------------*/
4505 
4506     if (pFormInfo->advQueryNextToken != NULL && pFormInfo->advQueryNextToken->choice == LEXTOK_RPAREN) {
4507       CloseGroup (pFormInfo);
4508       AdvQueryGetNextToken (pFormInfo);
4509     } else {
4510       ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "Missing right paren");
4511       return FALSE;
4512     }
4513 
4514     return TRUE;
4515   }
4516 
4517   /*--------------------------*/
4518   /* Otherwise, grab the term */
4519   /*--------------------------*/
4520 
4521   if (pFormInfo->advQueryNextToken->choice != LEXTOK_STRING) {
4522     ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "invalid token");
4523     return FALSE;
4524   }
4525 
4526   term = (CharPtr) (pFormInfo->advQueryNextToken->data.ptrvalue);
4527   AdvQueryGetNextToken (pFormInfo);
4528 
4529   /*---------------------------------------*/
4530   /* If it's a range, grab the second term */
4531   /*---------------------------------------*/
4532 
4533   if ((pFormInfo->advQueryNextToken != NULL) && (pFormInfo->advQueryNextToken->choice == LEXTOK_RANGE)) {
4534     AdvQueryGetNextToken (pFormInfo);
4535     if ((pFormInfo->advQueryNextToken == NULL) || (pFormInfo->advQueryNextToken->choice != LEXTOK_STRING)) {
4536       ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "missing second half of range");
4537       MemFree (term);
4538       return FALSE;
4539     }
4540     highRangeStr = (CharPtr) (pFormInfo->advQueryNextToken->data.ptrvalue);
4541     AdvQueryGetNextToken (pFormInfo);
4542   }
4543 
4544   /*----------------------*/
4545   /* Parse the field name */
4546   /*----------------------*/
4547 
4548   if ((pFormInfo->advQueryNextToken != NULL) && (pFormInfo->advQueryNextToken->choice == LEXTOK_LBRACKET)) {
4549 
4550       /*----------------------*/
4551     /* Get the field string */
4552       /*----------------------*/
4553 
4554     AdvQueryGetNextToken (pFormInfo);
4555     if ((pFormInfo->advQueryNextToken == NULL) || (pFormInfo->advQueryNextToken->choice != LEXTOK_STRING)) {
4556       ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "missing field id after bracket");
4557       MemFree (term);
4558       MemFree (highRangeStr);
4559       return FALSE;
4560     }
4561 
4562     fldStr = (CharPtr) (pFormInfo->advQueryNextToken->data.ptrvalue);
4563 
4564       /*-------------------------------------*/
4565     /* Convert string to field ID, mapping */
4566     /* wildcard '*' to 'ALL'.              */
4567       /*-------------------------------------*/
4568 
4569     if (fldStr != NULL && StrCmp (fldStr, "*") == 0)
4570       fld = FieldGetIDFromName (db, "ALL");
4571     else
4572       fld = FieldGetIDFromName (db, fldStr);
4573 
4574     MemFree (pFormInfo->advQueryNextToken->data.ptrvalue);
4575     if (fld < 0) {
4576       ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "bad field identifier");
4577       MemFree (term);
4578       MemFree (highRangeStr);
4579       return FALSE;
4580     }
4581 
4582       /*----------------------------------*/
4583     /* Check to see if the fields are a */
4584     /* comma-seperated range.           */
4585       /*----------------------------------*/
4586 
4587     AdvQueryGetNextToken (pFormInfo);
4588     if ((pFormInfo->advQueryNextToken == NULL) ||
4589         (pFormInfo->advQueryNextToken->choice != LEXTOK_COMMA && pFormInfo->advQueryNextToken->choice != LEXTOK_RBRACKET)) {
4590       ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "missing right bracket");
4591       MemFree (term);
4592       MemFree (highRangeStr);
4593       return FALSE;
4594     }
4595     if (pFormInfo->advQueryNextToken->choice == LEXTOK_COMMA) {
4596       AdvQueryGetNextToken (pFormInfo);
4597       if ((pFormInfo->advQueryNextToken == NULL) ||
4598           (pFormInfo->advQueryNextToken->choice != LEXTOK_STRING) || StringCmp (pFormInfo->advQueryNextToken->data.ptrvalue, "S") != 0) {
4599         ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "field qualifier error");
4600         MemFree (term);
4601         MemFree (highRangeStr);
4602         return FALSE;
4603       }
4604       MemFree (pFormInfo->advQueryNextToken->data.ptrvalue);
4605       AdvQueryGetNextToken (pFormInfo);
4606       if ((pFormInfo->advQueryNextToken == NULL) || (pFormInfo->advQueryNextToken->choice != LEXTOK_RBRACKET)) {
4607         ErrPostEx (SEV_WARNING, ERR_CD_LEX, 0, "missing right bracket");
4608         MemFree (term);
4609         MemFree (highRangeStr);
4610         return FALSE;
4611       }
4612     }
4613     AdvQueryGetNextToken (pFormInfo);
4614   }
4615 
4616   /*-------------------------------------*/
4617   /* Add in the high range, if it exists */
4618   /*-------------------------------------*/
4619 
4620   if (highRangeStr != NULL) {
4621     StringCat (term, ":");
4622     StringCat (term, highRangeStr);
4623   }
4624 
4625   /*-----------------------------------------------*/
4626   /* Create a new term and add it to the term list */
4627   /*-----------------------------------------------*/
4628 
4629   newTermPtr = Query_AddBoolTerm (pFormInfo->form, db, fld, term, STATE_ON, 0);
4630 
4631   if (newTermPtr == NULL) return FALSE;
4632 
4633   /*---------------------------------------*/
4634   /* Select the proper operator with which */
4635   /* to connect it to the previous term.   */
4636   /*---------------------------------------*/
4637 
4638   switch (currOp) {
4639     case LEXCHAR_OR:
4640       nOperator = ENTREZ_OP_OR;
4641       break;
4642     case LEXCHAR_AND:
4643       nOperator = ENTREZ_OP_AND;
4644       break;
4645     case LEXCHAR_NOT:
4646       nOperator = ENTREZ_OP_BUTNOT;
4647       break;
4648     default:
4649       nOperator = ENTREZ_OP_NONE;
4650       break;
4651   }
4652   newTermPtr->above = nOperator;
4653   if (newTermPtr->prev != NULL)
4654     newTermPtr->prev->below = nOperator;
4655 
4656   /*-------------------------------*/
4657   /* Set its group status properly */
4658   /*-------------------------------*/
4659 
4660   if (pFormInfo->advQueryNewGroup == TRUE) {
4661     newTermPtr->group = GROUP_FIRST;
4662     pFormInfo->advQueryNewGroup = FALSE;
4663   } else if (newTermPtr->prev != NULL) {
4664     switch (newTermPtr->prev->group) {
4665       case GROUP_SINGLE:
4666         newTermPtr->group = GROUP_SINGLE;
4667         break;
4668       case GROUP_FIRST:
4669       case GROUP_MIDDLE:
4670         newTermPtr->group = GROUP_MIDDLE;
4671         break;
4672       default:
4673         newTermPtr->group = GROUP_SINGLE;
4674         break;
4675     }
4676   }
4677 
4678 
4679 /*----------------------------------*/
4680 /* Clean up and return successfully */
4681 /*----------------------------------*/
4682 
4683   MemFree (term);
4684   MemFree (highRangeStr);
4685 
4686   return TRUE;
4687 }
4688 
4689 /*===================================================================*/
4690 /*                                                                   */
4691 /*  Query_ParseString () -                                           */
4692 /*                                                                   */
4693 /*     NOTE -- This function is based on EntrezPMTLParseString()     */
4694 /*             from accutil.c                                        */
4695 /*                                                                   */
4696 /*===================================================================*/
4697 
4698 static Boolean Query_ParseString (ForM f, CharPtr str, Int2 db, Int2 fld)
4699 
4700 {
4701   Boolean      retval;
4702   FormInfoPtr  pFormInfo;
4703 
4704   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
4705 
4706   /*---------------------------*/
4707   /* Check parameters, setting */
4708   /* defaults if necessary.    */
4709   /*---------------------------*/
4710 
4711   if (str == NULL || *str == '\0') return FALSE;
4712 
4713   /*------------------------------------*/
4714   /* Clear out the existing query terms */
4715   /*------------------------------------*/
4716 
4717   AdvQueryInit (pFormInfo, str);
4718 
4719   /*------------------------------------*/
4720   /* Recursively parse the query string */
4721   /*------------------------------------*/
4722 
4723   AdvQueryGetNextToken (pFormInfo);
4724 
4725   if ((ParseNOTedTerms (pFormInfo, db, fld, 0) == TRUE) && (pFormInfo->advQueryNextToken == NULL))
4726     retval = TRUE;
4727   else {
4728     ResetChosen (pFormInfo);
4729     retval = FALSE;
4730   }
4731 
4732   /*---------------------*/
4733   /* Return successfully */
4734   /*---------------------*/
4735 
4736   return retval;
4737 }
4738 
4739 /*==================================================================*/
4740 /*                                                                  */
4741 /*  AdvancedQueryText_Callback () -                                 */
4742 /*                                                                  */
4743 /*==================================================================*/
4744 
4745 static void AdvancedQueryText_Callback (TexT queryTextBox)
4746 
4747 {
4748   CharPtr      curstr;
4749   FormInfoPtr  pFormInfo;
4750 
4751   pFormInfo = (FormInfoPtr) GetObjectExtra (queryTextBox);
4752 
4753   curstr = SaveStringFromText (pFormInfo->advQueryText);
4754 
4755   if (Query_ParseString (pFormInfo->form, curstr, pFormInfo->currDb, -1)) {
4756 
4757     SafeEnable (pFormInfo->advRetrieveButton);
4758     pFormInfo->advQueryState = ADV_QUERY_EVALUATE_STATE;
4759     SafeSetTitle (pFormInfo->advRetrieveButton, "Evaluate");
4760   } else {
4761     SafeDisable (pFormInfo->advRetrieveButton);
4762     pFormInfo->advQueryState = ADV_QUERY_INVALID_STATE;
4763   }
4764 
4765   MemFree (curstr);
4766 }
4767 
4768 /*==================================================================*/
4769 /*                                                                  */
4770 /*  SetAdvancedText () -                                            */
4771 /*                                                                  */
4772 /*==================================================================*/
4773 
4774 static void SetAdvancedText (TexT advancedText, CharPtr str)
4775 
4776 {
4777   SetTitle (advancedText, str);
4778 }
4779 
4780 /*==================================================================*/
4781 /*                                                                  */
4782 /*  RepopulateChosen () -                                           */
4783 /*                                                                  */
4784 /*==================================================================*/
4785 
4786 static void RepopulateChosen (FormInfoPtr pFormInfo)
4787 
4788 {
4789   Int4          off;
4790   BaR           sb;
4791   StateDataPtr  sdp;
4792   Char          strn [256];
4793 
4794   sb = GetSlateVScrollBar ((SlatE) pFormInfo->chosenDoc);
4795   off = GetBarValue (sb);
4796   Reset (pFormInfo->chosenDoc);
4797 
4798   InvalDocument (pFormInfo->chosenDoc);
4799   pFormInfo->chosenNumLines = 0;
4800   for (sdp = pFormInfo->termList; sdp != NULL; sdp = sdp->next) {
4801     (pFormInfo->chosenNumLines)++;
4802     if (sdp->field == NULL)
4803       sprintf (strn, "%s\t [----]\t%ld\n", sdp->term, (long) sdp->count);
4804     else
4805       sprintf (strn, "%s\t [%s]\t%ld\n", sdp->term, sdp->field, (long) sdp->count);
4806     AppendText (pFormInfo->chosenDoc, strn, &chosenParFmt, chosenColFmt, systemFont);
4807   }
4808   InvalDocument (pFormInfo->chosenDoc);
4809   AdjustDocScroll (pFormInfo->chosenDoc);
4810   CorrectBarValue (sb, off);
4811   Update ();
4812 }
4813 
4814 /*==================================================================*/
4815 /*                                                                  */
4816 /*  Query_ConvertToString () - Convert the current linked list of   */
4817 /*                            terms into a string that can be       */
4818 /*                            displayed in the advanced query win.  */
4819 /*                                                                  */
4820 /*==================================================================*/
4821 
4822 static CharPtr Query_ConvertToString (ForM f)
4823 
4824 {
4825   Entrez2FieldInfoPtr  fieldInfo;
4826   Int2                 group;
4827   Int2                 last;
4828   CharPtr              ptr;
4829   StateDataPtr         sdp;
4830   CharPtr              tmp;
4831   CharPtr              advQueryString;
4832   FormInfoPtr          pFormInfo;
4833 
4834   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
4835 
4836   if (pFormInfo->termList == NULL) return NULL;
4837 
4838   if (pFormInfo->chosenNumLines < 1) return NULL;
4839 
4840   advQueryString = MemNew (1000);
4841   advQueryString [0] = '\0';
4842   group = 0;
4843   last = 0;
4844   for (sdp = pFormInfo->termList; sdp != NULL; sdp = sdp->next) {
4845     if (sdp->group == GROUP_SINGLE || sdp->group == GROUP_FIRST)
4846       group++;
4847 
4848     if (sdp->state == STATE_ON) {
4849       if (last == 0) {
4850         StrCat (advQueryString, "( ");
4851         StrCat (advQueryString, "( ");
4852       } else if (last == group) {
4853         StrCat (advQueryString, " | ");
4854       } else if (sdp->above == ENTREZ_OP_BUTNOT) {
4855         StrCat (advQueryString, " )");
4856         StrCat (advQueryString, " )");
4857         StrCat (advQueryString, " - ");
4858         StrCat (advQueryString, "( ");
4859         StrCat (advQueryString, "( ");
4860       } else {
4861         StrCat (advQueryString, " )");
4862         StrCat (advQueryString, " & ");
4863         StrCat (advQueryString, "( ");
4864       }
4865       StringCat (advQueryString, "\"");
4866       tmp = StringSave (sdp->term);
4867       ptr = StringChr (tmp, ':');
4868       if (ptr != NULL) {
4869         *ptr = '\0';
4870         ptr++;
4871         TrimSpacesAroundString (tmp);
4872         TrimSpacesAroundString (ptr);
4873         StringCat (advQueryString, tmp);
4874         StringCat (advQueryString, "\" : \"");
4875         StringCat (advQueryString, ptr);
4876       } else
4877         StringCat (advQueryString, tmp);
4878       MemFree (tmp);
4879       StringCat (advQueryString, "\"[");
4880       fieldInfo = FieldGetInfo (sdp->db, sdp->fld);
4881       StringCat (advQueryString, fieldInfo->field_name);
4882       StringCat (advQueryString, "]");
4883       last = group;
4884     }
4885   }
4886 
4887   if (group > 0 && last > 0) {
4888     StrCat (advQueryString, " )");
4889     StrCat (advQueryString, " )");
4890   }
4891 
4892   return advQueryString;
4893 }
4894 
4895 /*==================================================================*/
4896 /*                                                                  */
4897 /*  AdvancedQueryToggle_Callback () - Called when the "Advanced     */
4898 /*                                   Queries" menu option is        */
4899 /*                                   selected.                      */
4900 /*                                                                  */
4901 /*==================================================================*/
4902 
4903 static void AdvancedQueryToggle_Callback (IteM i)
4904 
4905 {
4906   FormInfoPtr  pFormInfo;
4907   CharPtr      str;
4908 
4909   pFormInfo = (FormInfoPtr) GetObjectExtra (i);
4910 
4911   /*-----------------------*/
4912   /* Advanced ==> Standard */
4913   /*-----------------------*/
4914 
4915   if (! GetStatus (pFormInfo->advancedQueryItem)) {
4916     SafeHide (pFormInfo->advQueryGroup);
4917     Reset (pFormInfo->advQueryText);
4918     RepopulateChosen (pFormInfo);
4919     SafeShow (pFormInfo->stdQueryGroup);
4920   }
4921 
4922   /*-----------------------*/
4923   /* Standard ==> Advanced */
4924   /*-----------------------*/
4925 
4926   else {
4927     str = Query_ConvertToString (pFormInfo->form);
4928     SetAdvancedText (pFormInfo->advQueryText, str);
4929     MemFree (str);
4930     SafeHide (pFormInfo->stdQueryGroup);
4931     SafeShow (pFormInfo->advQueryGroup);
4932   }
4933 }
4934 
4935 /*==================================================================*/
4936 /*                                                                  */
4937 /*  ExplodeTermsToggle_Callback () - Called when the "Explode       */
4938 /*                                   Terms" menu option is          */
4939 /*                                   selected.                      */
4940 /*                                                                  */
4941 /*==================================================================*/
4942 
4943 static void ExplodeTermsToggle_Callback (IteM i)
4944 
4945 {
4946   FormInfoPtr  pFormInfo;
4947 
4948   pFormInfo = (FormInfoPtr) GetObjectExtra (i);
4949   if (pFormInfo == NULL) return;
4950 
4951   WatchCursor ();
4952   Update ();
4953   RecalculateChosen (pFormInfo);
4954   ArrowCursor ();
4955   Update ();
4956 }
4957 
4958 /*===================================================================*/
4959 /*                                                                   */
4960 /*  TermList_UnselectAll () -- Marks all terms in the term list as   */
4961 /*                            unselected.                            */
4962 /*                                                                   */
4963 /*===================================================================*/
4964 
4965 NLM_EXTERN Boolean TermList_UnselectAll (ForM f)
4966 
4967 {
4968   Int2          count = 0;
4969   Int2          item;
4970   FormInfoPtr   pFormInfo;
4971   StateDataPtr  sdp;
4972 
4973   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
4974 
4975   sdp = pFormInfo->termList;
4976   while (sdp != NULL) {
4977     sdp->state = STATE_OFF;
4978     sdp = sdp->next;
4979     count++;
4980   }
4981 
4982   ResetClip ();
4983   WatchCursor ();
4984   for (item = 1; item <= count; item++) {
4985     InvalDocCols (pFormInfo->chosenDoc, item, 3, 3);
4986   }
4987   Update ();
4988   RecalculateChosen (pFormInfo);
4989   ArrowCursor ();
4990 
4991   return TRUE;
4992 }
4993 
4994 /*==================================================================*/
4995 /*                                                                  */
4996 /*  AlphabetizeGroups () -                                          */
4997 /*                                                                  */
4998 /*==================================================================*/
4999 
5000 static void AlphabetizeGroups (FormInfoPtr pFormInfo)
5001 
5002 {
5003   Int2          compare;
5004   Boolean       keepGoing;
5005   StateDataPtr  next;
5006   StateDataPtr  sdp;
5007   StateData     tmp;
5008 
5009   if (pFormInfo->termList == NULL) return;
5010 
5011   keepGoing = TRUE;
5012   while (keepGoing) {
5013     keepGoing = FALSE;
5014     for (sdp = pFormInfo->termList; sdp->next != NULL; sdp = sdp->next) {
5015       next = sdp->next;
5016       if (sdp->group == GROUP_FIRST || sdp->group == GROUP_MIDDLE) {
5017         compare = MeshStringICmp (sdp->term, next->term);
5018         if (compare > 0) {
5019           tmp.term = next->term;
5020           tmp.field = next->field;
5021           tmp.count = next->count;
5022           tmp.db = next->db;
5023           tmp.fld = next->fld;
5024           next->term = sdp->term;
5025           next->field = sdp->field;
5026           next->count = sdp->count;
5027           next->db = sdp->db;
5028           next->fld = sdp->fld;
5029           sdp->term = tmp.term;
5030           sdp->field = tmp.field;
5031           sdp->count = tmp.count;
5032           sdp->db = tmp.db;
5033           sdp->fld = tmp.fld;
5034           keepGoing = TRUE;
5035         }
5036       }
5037     }
5038   }
5039 }
5040 
5041 /*==================================================================*/
5042 /*                                                                  */
5043 /*  Query_ClearUnusedTerms () - Remove any terms that have been     */
5044 /*                              turned off.                         */
5045 /*                                                                  */
5046 /*==================================================================*/
5047 
5048 static void Query_ClearUnusedTerms (IteM i)
5049 
5050 {
5051   StateDataPtr       next;
5052   StateDataPtr       sdp;
5053   FormInfoPtr        pFormInfo;
5054 
5055   pFormInfo = (FormInfoPtr) GetObjectExtra (i);
5056 
5057   WatchCursor ();
5058   Update ();
5059 
5060   /* Iterate through the list, removing all */
5061   /* terms that are marked as unused.       */
5062 
5063   sdp = pFormInfo->termList;
5064 
5065   while (sdp != NULL) {
5066     next = sdp->next;
5067     if (sdp->state == STATE_OFF) {
5068       RemoveTermFromList (pFormInfo, sdp, FALSE, FALSE);
5069       FreeTerm (sdp);
5070     }
5071     sdp = next;
5072   }
5073 
5074   /* Adjust the display accordingly */
5075 
5076   AlphabetizeGroups (pFormInfo);
5077   RepopulateChosen (pFormInfo);
5078   RecalculateChosen (pFormInfo);
5079   ArrowCursor ();
5080 }
5081 
5082 /*==================================================================*/
5083 /*                                                                  */
5084 /*  SetupMenus () - Create and initialize the pulldown menus.       */
5085 /*                                                                  */
5086 /*==================================================================*/
5087 
5088 static void SetupMenus (WindoW w, FormInfoPtr pFormInfo, Boolean explodeToggle, Boolean advancedQueryToggle)
5089 
5090 {
5091   IteM  clearUnusedItem;
5092   MenU  m;
5093   MenU  s;
5094 
5095   /*-----------*/
5096   /* File menu */
5097   /*-----------*/
5098 
5099   m = PulldownMenu (w, "File");
5100   CommandItem (m, "Import UID List.../I", ImportUIDs_Callback);
5101   CommandItem (m, "Export UID List.../E", ExportUIDs_Callback);
5102   SeparatorItem (m);
5103   CommandItem (m, "Quit/Q", Quit_Callback);
5104 
5105   /*-----------*/
5106   /* Edit menu */
5107   /*-----------*/
5108 
5109   m = PulldownMenu (w, "Edit");
5110   FormCommandItem (m, CUT_MENU_ITEM, (BaseFormPtr) pFormInfo, VIB_MSG_CUT);
5111   FormCommandItem (m, COPY_MENU_ITEM, (BaseFormPtr) pFormInfo, VIB_MSG_COPY);
5112   FormCommandItem (m, PASTE_MENU_ITEM, (BaseFormPtr) pFormInfo, VIB_MSG_PASTE);
5113   FormCommandItem (m, CLEAR_MENU_ITEM, (BaseFormPtr) pFormInfo, VIB_MSG_DELETE);
5114 
5115   /*--------------*/
5116   /* Options menu */
5117   /*--------------*/
5118 
5119   m = PulldownMenu (w, "Options");
5120 
5121   clearUnusedItem = CommandItem (m, "Clear Unused Query Terms", Query_ClearUnusedTerms);
5122   SetObjectExtra (clearUnusedItem, pFormInfo, NULL);
5123   pFormInfo->advancedQueryItem = StatusItem (m, "Advanced Queries", AdvancedQueryToggle_Callback);
5124   SetStatus (pFormInfo->advancedQueryItem, advancedQueryToggle);
5125   SetObjectExtra (pFormInfo->advancedQueryItem, pFormInfo, NULL);
5126 
5127   pFormInfo->explodeItem = StatusItem (m, "Explode Terms", ExplodeTermsToggle_Callback);
5128   SetStatus (pFormInfo->explodeItem, explodeToggle);
5129   SetObjectExtra (pFormInfo->explodeItem, pFormInfo, NULL);
5130 
5131   s = SubMenu (m, "Show ASN.1");
5132   s_showASNItem = ChoiceGroup (s, NULL);
5133   ChoiceItem (s_showASNItem, "OFF");
5134   ChoiceItem (s_showASNItem, "1");
5135   ChoiceItem (s_showASNItem, "2");
5136   ChoiceItem (s_showASNItem, "3");
5137   ChoiceItem (s_showASNItem, "4");
5138   ChoiceItem (s_showASNItem, "5");
5139   ChoiceItem (s_showASNItem, "6");
5140   ChoiceItem (s_showASNItem, "7");
5141   ChoiceItem (s_showASNItem, "8");
5142   ChoiceItem (s_showASNItem, "9");
5143   ChoiceItem (s_showASNItem, "ON");
5144   ChoiceItem (s_showASNItem, "LOG");
5145   SetValue (s_showASNItem, 1);
5146 
5147   /*------------*/
5148   /* Help menu */
5149   /*------------*/
5150 
5151   m = PulldownMenu (w, "Help");
5152   CommandItem (m, "Databases...", DatabaseView_Callback);
5153   CommandItem (m, "Fields...", FieldView_Callback);
5154   CommandItem (m, "Modes...", ModeView_Callback);
5155 }
5156 
5157 /*==================================================================*/
5158 /*                                                                  */
5159 /*  SetupAdvQueryGroup () - Create and initialize the Advanced      */
5160 /*                          Query Form.                             */
5161 /*                                                                  */
5162 /*==================================================================*/
5163 
5164 static GrouP SetupAdvQueryGroup (FormInfoPtr pFormInfo, GrouP mainGroup)
5165 
5166 {
5167   GrouP   advQueryGroup;
5168   GrouP   buttonGroup;
5169   GrouP   instructionGroup;
5170   Char    tempStr [256];
5171 
5172   advQueryGroup = HiddenGroup (mainGroup, -1, 0, NULL);
5173   SetGroupSpacing (advQueryGroup, 5, 5);
5174 
5175   /*----------------------------------*/
5176   /* Set up alternative boolean query */
5177   /* refinement text edit box.        */
5178   /*----------------------------------*/
5179 
5180   pFormInfo->advQueryText = ScrollText (advQueryGroup, ADV_TEXT_WIDTH, ADV_TEXT_HEIGHT, programFont, TRUE, AdvancedQueryText_Callback);
5181   SetObjectExtra (pFormInfo->advQueryText, pFormInfo, NULL);
5182 
5183   /*------------------------------------------*/
5184   /* Create a group for the Retrieve/Evaluate */
5185   /* combined button and the Reset button.    */
5186   /*------------------------------------------*/
5187 
5188   buttonGroup = HiddenGroup (advQueryGroup, 5, 0, NULL);
5189   SetGroupSpacing (buttonGroup, 10, 10);
5190 
5191   pFormInfo->advRetrieveButton = PushButton (buttonGroup, "Retrieve 000000000 Documents", EvaluateRetrieve_Callback);
5192   SetObjectExtra (pFormInfo->advRetrieveButton, pFormInfo, NULL);
5193   SetTitle (pFormInfo->advRetrieveButton, "Evaluate");
5194   Disable (pFormInfo->advRetrieveButton);
5195   pFormInfo->advQueryState = ADV_QUERY_INVALID_STATE;
5196 
5197   pFormInfo->advResetButton = PushButton (buttonGroup, "Reset", Reset_Callback);
5198   SetObjectExtra (pFormInfo->advResetButton, pFormInfo, NULL);
5199 
5200   /*----------------------------------------------*/
5201   /* Create instructions for using advanced query */
5202   /*----------------------------------------------*/
5203 
5204   instructionGroup = HiddenGroup (advQueryGroup, 1, 0, NULL);
5205   StaticPrompt (instructionGroup, "Operators:", 0, 0, programFont, 'l');
5206   StaticPrompt (instructionGroup, "", 0, 0, programFont, 'l');
5207   StaticPrompt (instructionGroup, "    & (and)", 0, 0, programFont, 'l');
5208   StaticPrompt (instructionGroup, "    | (or)", 0, 0, programFont, 'l');
5209   StaticPrompt (instructionGroup, "    - (butnot)", 0, 0, programFont, 'l');
5210   StaticPrompt (instructionGroup, "    : (range)", 0, 0, programFont, 'l');
5211   StaticPrompt (instructionGroup, "", 0, 0, programFont, 'l');
5212   StaticPrompt (instructionGroup, "Example:", 0, 0, programFont, 'l');
5213   StaticPrompt (instructionGroup, "", 0, 0, programFont, 'l');
5214   tempStr [0] = '\0';
5215   StringCat (tempStr, "    ((\"glucagon\" [WORD] | \"insulin\" ");
5216   StringCat (tempStr, "[MESH]) & (\"1995\" : \"1996\" [PDAT]))");
5217   StaticPrompt (instructionGroup, tempStr, 0, 0, programFont, 'l');
5218   StaticPrompt (instructionGroup, "", 0, 0, programFont, 'l');
5219   StaticPrompt (instructionGroup, "Use [*] to search all fields.", 0, 0, programFont, 'l');
5220 
5221   /*--------------------------------*/
5222   /* Return the newly created group */
5223   /*--------------------------------*/
5224 
5225   return advQueryGroup;
5226 }
5227 
5228 /*==================================================================*/
5229 /*                                                                  */
5230 /*  GetValueFromField () -                                          */
5231 /*                                                                  */
5232 /*==================================================================*/
5233 
5234 static Int4 GetValueFromField (DoC d, Int2 item, Int2 row, Int2 col)
5235 
5236 {
5237   CharPtr  str;
5238   Int4     value;
5239 
5240   value = -1;
5241   str = GetDocText (d, item, row, col);
5242   if (str != NULL) {
5243     if (! StrToLong (str, &value)) {
5244       value = -1;
5245     }
5246   }
5247 
5248   MemFree (str);
5249   return value;
5250 }
5251 
5252 /*==================================================================*/
5253 /*                                                                  */
5254 /*  DrawAvailLeaf () -                                              */
5255 /*                                                                  */
5256 /*==================================================================*/
5257 
5258 static void DrawAvailLeaf (DoC d, RectPtr r, Int2 item, Int2 frst)
5259 
5260 {
5261   RecT  q;
5262   Int2  value;
5263 
5264   if (r == NULL || frst != 0) return;
5265 
5266   value = GetValueFromField (d, item, 1, 3);
5267   if (value != 1) return;
5268 
5269   q = *r;
5270   q.left++;
5271   q.right = q.left + 4;
5272   q.top += stdLineHeight / 2 - 2;
5273   q.bottom = q.top + 4;
5274   value = GetValueFromField (d, item, 1, 3);
5275   if (value == STATE_ON) {
5276     /*
5277        InvertColors ();
5278     */
5279     EraseRect (&q);
5280     PaintRect (&q);
5281     /*
5282        InvertColors ();
5283     */
5284   } else
5285     PaintRect (&q);
5286 }
5287 
5288 /*==================================================================*/
5289 /*                                                                  */
5290 /*  HighlightAvail () -                                             */
5291 /*                                                                  */
5292 /*==================================================================*/
5293 
5294 static Boolean HighlightAvail (DoC d, Int2 item, Int2 row, Int2 col)
5295 
5296 {
5297   FormInfoPtr  pFormInfo;
5298 
5299   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
5300 
5301   if (item == pFormInfo->availItem && row == pFormInfo->availRow) return TRUE;
5302 
5303   return FALSE;
5304 }
5305 
5306 /*==================================================================*/
5307 /*                                                                  */
5308 /*  ClickAvail () -                                                 */
5309 /*                                                                  */
5310 /*==================================================================*/
5311 
5312 static void ClickAvail (DoC d, PoinT pt)
5313 
5314 {
5315   Int2         item;
5316   Int2         row;
5317   FormInfoPtr  pFormInfo;
5318 
5319   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
5320 
5321   MapDocPoint (d, pt, &item, &row, NULL, NULL);
5322   pFormInfo->availClickItem = item;
5323   pFormInfo->availClickRow = row;
5324   pFormInfo->wasDoubleClick = dblClick;
5325 
5326   SafeEnable (pFormInfo->acceptButton);
5327 }
5328 
5329 /*==================================================================*/
5330 /*                                                                  */
5331 /*  ReleaseAvail () - This is called whenever the mouse button is   */
5332 /*                   realeased in the term selection window.        */
5333 /*                                                                  */
5334 /*==================================================================*/
5335 
5336 static void ReleaseAvail (DoC d, PoinT pt)
5337 
5338 {
5339   Char         ch;
5340   Int2         item;
5341   Int2         olditem;
5342   Int2         oldrow;
5343   CharPtr      ptr;
5344   Int2         row;
5345   CharPtr      text;
5346   Int4         iTermCount;
5347   CharPtr      sTermCount;
5348   FormInfoPtr  pFormInfo;
5349 
5350   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
5351 
5352   /*------------------------------------*/
5353   /* Convert the screen location of the */
5354   /* release into an item and a row.    */
5355   /*------------------------------------*/
5356 
5357   MapDocPoint (d, pt, &item, &row, NULL, NULL);
5358 
5359   /* ---------------------------------------- */
5360   /* There's no dragging in the avail window */
5361   /* ---------------------------------------- */
5362 
5363   if (pFormInfo->availClickItem != item || pFormInfo->availClickRow != row) return;
5364 
5365   text = GetDocText (pFormInfo->availDoc, item, row, 1);
5366   if (StringHasNoText (text)) {
5367     text = MemFree (text);
5368   }
5369 
5370   olditem = pFormInfo->availItem;
5371   oldrow = pFormInfo->availRow;
5372   if (text != NULL) {
5373     pFormInfo->availItem = item;
5374     pFormInfo->availRow = row;
5375   } else {
5376     pFormInfo->availItem = 0;
5377     pFormInfo->availRow = 0;
5378   }
5379   if (olditem > 0 && oldrow > 0)
5380     InvalDocRows (pFormInfo->availDoc, olditem, oldrow, oldrow);
5381   if (text != NULL && item > 0 && row > 0)
5382     InvalDocRows (pFormInfo->availDoc, item, row, row);
5383 
5384   if (text != NULL) {
5385     ptr = text;
5386     ch = *ptr;
5387     while (ch != '\0' && ch >= ' ') {
5388       ptr++;
5389       ch = *ptr;
5390     }
5391     *ptr = '\0';
5392     if (pFormInfo->currMode == RANGE_MODE) {
5393       if (CurrentText () == pFormInfo->fromText) {
5394         SafeSetTitle (pFormInfo->fromText, text);
5395         Select (pFormInfo->fromText);
5396       } else if (CurrentText () == pFormInfo->toText) {
5397         SafeSetTitle (pFormInfo->toText, text);
5398         Select (pFormInfo->toText);
5399       }
5400     } else {
5401       SafeSetTitle (pFormInfo->termText, text);
5402       Select (pFormInfo->termText);
5403     }
5404     Update ();
5405   } else {
5406     if (pFormInfo->currMode == RANGE_MODE) {
5407       SafeSetTitle (pFormInfo->fromText, "");
5408       SafeSetTitle (pFormInfo->toText, "");
5409       Select (pFormInfo->fromText);
5410     } else {
5411       SafeSetTitle (pFormInfo->termText, "");
5412       Select (pFormInfo->termText);
5413     }
5414     Update ();
5415   }
5416 
5417   if (text != NULL && pFormInfo->wasDoubleClick) {
5418     WatchCursor ();
5419     Update ();
5420 
5421     if ((pFormInfo->currMode == TAXONOMY_MODE) || (pFormInfo->currMode == MESH_TREE_MODE)) {
5422       Update ();
5423       ResetClip ();             /* clipped to panel, need to update popup */
5424       RepopulateTaxonomy (pFormInfo, text);
5425     } else if (pFormInfo->currMode == RANGE_MODE) {
5426       ResetClip ();
5427       sTermCount = GetDocText (pFormInfo->availDoc, pFormInfo->availItem,
5428                                pFormInfo->availRow, E2_COUNT_COL);
5429       TrimSpacesAroundString (sTermCount);
5430       iTermCount = atoi (sTermCount);
5431       MemFree (sTermCount);
5432       Query_AddBoolTerm (pFormInfo->form, pFormInfo->currDb,
5433                          pFormInfo->currField, text, STATE_ON, iTermCount);
5434       Update ();
5435       RecalculateChosen (pFormInfo);
5436     } else {
5437       ResetClip ();
5438       sTermCount = GetDocText (pFormInfo->availDoc, pFormInfo->availItem,
5439                                pFormInfo->availRow, E2_COUNT_COL);
5440       TrimSpacesAroundString (sTermCount);
5441       iTermCount = atoi (sTermCount);
5442       MemFree (sTermCount);
5443       Query_AddBoolTerm (pFormInfo->form, pFormInfo->currDb,
5444                          pFormInfo->currField, text, STATE_ON, iTermCount);
5445       Update ();
5446       RecalculateChosen (pFormInfo);
5447     }
5448 
5449     ArrowCursor ();
5450   }
5451   MemFree (text);
5452 }
5453 
5454 /*==================================================================*/
5455 /*                                                                  */
5456 /*  AvailTimerProc () -                                             */
5457 /*                                                                  */
5458 /*==================================================================*/
5459 
5460 static void AvailTimerProc (WindoW w)
5461 
5462 {
5463   FormInfoPtr  pFormInfo;
5464 
5465   pFormInfo = (FormInfoPtr) GetObjectExtra (w);
5466   pFormInfo->okayToAccept = TRUE;
5467 }
5468 
5469 /*==================================================================*/
5470 /*                                                                  */
5471 /*  InitAvailPanel () - Set up the Term List Panel.                 */
5472 /*                                                                  */
5473 /*==================================================================*/
5474 
5475 static void InitAvailPanel (FormInfoPtr pFormInfo)
5476 
5477 {
5478   RecT  r;
5479 
5480   pFormInfo->availItem = 0;
5481   pFormInfo->availRow = 0;
5482   SetDocShade (pFormInfo->availDoc, DrawAvailLeaf, NULL, HighlightAvail, NULL);
5483   SetDocProcs (pFormInfo->availDoc, ClickAvail, NULL, ReleaseAvail, NULL);
5484   SetDocCache (pFormInfo->availDoc, NULL, NULL, NULL);
5485 
5486   ObjectRect (pFormInfo->availDoc, &r);
5487   InsetRect (&r, 4, 4);
5488   SelectFont (systemFont);
5489 
5490   availColFmt [1].pixWidth = StringWidth ("0000000") + 10;
5491   availColFmt [0].pixWidth = (r.right - r.left) - availColFmt [1].pixWidth;
5492   availColFmt [2].pixWidth = 0;
5493 
5494   SetDocAutoAdjust (pFormInfo->availDoc, FALSE);
5495 
5496   InvalDocument (pFormInfo->availDoc);
5497 }
5498 
5499 /*==================================================================*/
5500 /*                                                                  */
5501 /*  DrawChosenBrackets () - This is the draw callback for the       */
5502 /*                         Chosen document panel. It gets called    */
5503 /*                         every time the panel is drawn.           */
5504 /*                                                                  */
5505 /*==================================================================*/
5506 
5507 static void DrawChosenBrackets (DoC d, RectPtr r, Int2 item, Int2 frst)
5508 
5509 {
5510   FormInfoPtr   pFormInfo;
5511   RecT          s;
5512   StateDataPtr  sdp;
5513   static Uint1  andsign [] = { 0x30, 0x48, 0x50, 0x20, 0x50, 0x8A, 0x84, 0x8A, 0x71, 0x00 };
5514   static Uint1  notsign [] = { 0x00, 0x00, 0xFF, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 };
5515 
5516   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
5517 
5518   sdp = pFormInfo->termList;
5519   while (sdp != NULL && item > 1) {
5520     sdp = sdp->next;
5521     item--;
5522   }
5523   if (sdp == NULL) return;
5524 
5525   switch (sdp->group) {
5526     case GROUP_SINGLE:
5527       break;
5528     case GROUP_FIRST:
5529       MoveTo (r->left + 16 + 1, r->top + 1);
5530       LineTo (r->left + 16 + 3, r->top + 1);
5531       MoveTo (r->left + 16 + 1, r->top + 2);
5532       LineTo (r->left + 16 + 3, r->top + 2);
5533       MoveTo (r->left + 16 + 1, r->top + 1);
5534       LineTo (r->left + 16 + 1, r->bottom);
5535       break;
5536     case GROUP_MIDDLE:
5537       MoveTo (r->left + 16 + 1, r->top);
5538       LineTo (r->left + 16 + 1, r->bottom);
5539       break;
5540     case GROUP_LAST:
5541       MoveTo (r->left + 16 + 1, r->top);
5542       LineTo (r->left + 16 + 1, r->bottom - 1);
5543       MoveTo (r->left + 16 + 1, r->bottom - 2);
5544       LineTo (r->left + 16 + 3, r->bottom - 2);
5545       MoveTo (r->left + 16 + 1, r->bottom - 1);
5546       LineTo (r->left + 16 + 3, r->bottom - 1);
5547       break;
5548     default:
5549       break;
5550   }
5551 
5552   switch (sdp->above) {
5553     case ENTREZ_OP_NONE:
5554       break;
5555     case ENTREZ_OP_AND:
5556       LoadRect (&s, r->left + 6, r->top, r->left + 14, r->top + 5);
5557       CopyBits (&s, andsign + 5);
5558       break;
5559     case ENTREZ_OP_BUTNOT:
5560       LoadRect (&s, r->left, r->top, r->left + 8, r->top + 5);
5561       CopyBits (&s, notsign + 5);
5562       break;
5563     default:
5564       break;
5565   }
5566 
5567   switch (sdp->below) {
5568     case ENTREZ_OP_NONE:
5569       break;
5570     case ENTREZ_OP_AND:
5571       LoadRect (&s, r->left + 6, r->bottom - 5, r->left + 14, r->bottom);
5572       CopyBits (&s, andsign);
5573       break;
5574     case ENTREZ_OP_BUTNOT:
5575       LoadRect (&s, r->left, r->bottom - 5, r->left + 8, r->bottom);
5576       CopyBits (&s, notsign);
5577       break;
5578     default:
5579       break;
5580   }
5581 }
5582 
5583 /*==================================================================*/
5584 /*                                                                  */
5585 /*  HighlightChosen () -                                            */
5586 /*                                                                  */
5587 /*==================================================================*/
5588 
5589 static Boolean HighlightChosen (DoC d, Int2 item, Int2 row, Int2 col)
5590 
5591 {
5592   StateDataPtr  sdp;
5593   FormInfoPtr   pFormInfo;
5594 
5595   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
5596 
5597   if (col == 1 || col == 2) {
5598     if (pFormInfo->chosenInAboveBox || pFormInfo->chosenInBelowBox) return FALSE;
5599     /* if (item == pFormInfo->chosenItem) return TRUE; */
5600     return FALSE;
5601   } else if (col == 3) {
5602     sdp = pFormInfo->termList;
5603     while (sdp != NULL && item > 1) {
5604       sdp = sdp->next;
5605       item--;
5606     }
5607     if (sdp == NULL) return FALSE;
5608     return (Boolean) (sdp->state == STATE_ON);
5609   } else
5610     return FALSE;
5611 }
5612 
5613 /*==================================================================*/
5614 /*                                                                  */
5615 /*  FrameChosen () -                                                */
5616 /*                                                                  */
5617 /*==================================================================*/
5618 
5619 static void FrameChosen (FormInfoPtr pFormInfo)
5620 
5621 {
5622   RecT  sr;
5623 
5624   ObjectRect (pFormInfo->chosenDoc, &sr);
5625   InsetRect (&sr, 4, 4);
5626 
5627   if (RectInRect (&(pFormInfo->trackRect), &sr)) {
5628     Dotted ();
5629     FrameRect (&(pFormInfo->trackRect));
5630   }
5631 }
5632 
5633 /*==================================================================*/
5634 /*                                                                  */
5635 /*  ClickChosen () -                                                */
5636 /*                                                                  */
5637 /*==================================================================*/
5638 
5639 static void ClickChosen (DoC d, PoinT pt)
5640 
5641 {
5642   Int2         col;
5643   Int2         item;
5644   RecT         r;
5645   Int2         row;
5646   RecT         s;
5647   FormInfoPtr  pFormInfo;
5648 
5649   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
5650 
5651   MapDocPoint (d, pt, &item, &row, &col, &r);
5652   if (item > 0 && row == 0 && col > 0)
5653     row = 1;
5654 
5655   pFormInfo->chosenClickItem = item;
5656   pFormInfo->chosenClickRow = row;
5657   pFormInfo->chosenClickCol = col;
5658   pFormInfo->wasDoubleClick = dblClick;
5659   pFormInfo->chosenInAboveBox = FALSE;
5660   pFormInfo->chosenInBelowBox = FALSE;
5661 
5662   if ((col == 1 || col == 2) && (item > 0) && (item <= pFormInfo->chosenNumLines) && (row > 0)) {
5663     pFormInfo->chosenItem = item;
5664     LoadRect (&s, r.left, r.top, r.left + 16, r.top + 5);
5665     if (PtInRect (pt, &s))
5666       pFormInfo->chosenInAboveBox = TRUE;
5667     LoadRect (&s, r.left, r.bottom - 5, r.left + 16, r.bottom);
5668     if (PtInRect (pt, &s))
5669       pFormInfo->chosenInBelowBox = TRUE;
5670     if (pFormInfo->chosenInAboveBox || pFormInfo->chosenInBelowBox)
5671       return;
5672     InvalDocCols (pFormInfo->chosenDoc, item, 1, 2);
5673     Update ();
5674     r.right = r.left + chosenColFmt [0].pixWidth + chosenColFmt [1].pixWidth;
5675     LoadRect (&(pFormInfo->trackRect), r.left + 22, r.top, r.right - 2, r.bottom);
5676     pFormInfo->trackPt = pt;
5677     InvertMode ();
5678     FrameChosen (pFormInfo);
5679   } else
5680     pFormInfo->chosenItem = 0;
5681 }
5682 
5683 /*==================================================================*/
5684 /*                                                                  */
5685 /*  DragChosen () -                                                 */
5686 /*                                                                  */
5687 /*==================================================================*/
5688 
5689 static void DragChosen (DoC d, PoinT pt)
5690 
5691 {
5692   Int4         off;
5693   BaR          sb;
5694   RecT         sr;
5695   FormInfoPtr  pFormInfo;
5696 
5697   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
5698 
5699   if (pFormInfo->chosenItem == 0) return;
5700   if (pFormInfo->chosenInAboveBox || pFormInfo->chosenInBelowBox) return;
5701   InvertMode ();
5702   FrameChosen (pFormInfo);
5703   Update ();
5704   ObjectRect (pFormInfo->chosenDoc, &sr);
5705   InsetRect (&sr, 4, 4);
5706   if (PtInRect (pt, &sr)) {
5707     OffsetRect (&(pFormInfo->trackRect), 0, pt.y - pFormInfo->trackPt.y);
5708     pFormInfo->trackPt = pt;
5709   }
5710   sb = GetSlateVScrollBar ((SlatE) pFormInfo->chosenDoc);
5711   off = GetBarValue (sb);
5712   ResetClip ();
5713   if (pt.y < sr.top)
5714     SetBarValue (sb, off - 1);
5715   else if (pt.y > sr.bottom)
5716     SetBarValue (sb, off + 1);
5717   Update ();
5718   InvertMode ();
5719   FrameChosen (pFormInfo);
5720   Update ();
5721 }
5722 
5723 /*==================================================================*/
5724 /*                                                                  */
5725 /*  FlipOperatorBelow () -                                          */
5726 /*                                                                  */
5727 /*==================================================================*/
5728 
5729 static void FlipOperatorBelow (FormInfoPtr pFormInfo, Int2 item)
5730 
5731 {
5732   StateDataPtr  next;
5733   RecT          r;
5734   StateDataPtr  sdp;
5735 
5736   sdp = pFormInfo->termList;
5737   while (item > 1 && sdp != NULL) {
5738     item--;
5739     sdp = sdp->next;
5740   }
5741   if (sdp != NULL) {
5742     next = sdp->next;
5743     if (next != NULL) {
5744       if (sdp->below != next->above)
5745         Beep ();
5746       if (sdp->below == ENTREZ_OP_AND) {
5747         sdp->below = ENTREZ_OP_BUTNOT;
5748         next->above = ENTREZ_OP_BUTNOT;
5749       } else if (sdp->below == ENTREZ_OP_BUTNOT) {
5750         sdp->below = ENTREZ_OP_AND;
5751         next->above = ENTREZ_OP_AND;
5752       }
5753       ObjectRect (pFormInfo->chosenDoc, &r);
5754       InsetRect (&r, 4, 4);
5755       r.right = r.left + 16;
5756       Select (pFormInfo->chosenDoc);
5757       InvalRect (&r);
5758       ResetClip ();
5759       WatchCursor ();
5760       Update ();
5761       RecalculateChosen (pFormInfo);
5762       ArrowCursor ();
5763     }
5764   }
5765 }
5766 
5767 /*==================================================================*/
5768 /*                                                                  */
5769 /*  RemoveTermFromList () - Removes the given term from the given   */
5770 /*                           doubly-linked list of terms, and       */
5771 /*                           adjusts the surrounding terms          */
5772 /*                           accordingly.                           */
5773 /*                                                                  */
5774 /*==================================================================*/
5775 
5776 static Boolean RemoveTermFromList (FormInfoPtr pFormInfo, StateDataPtr sdp, Boolean goingDown, Boolean lastDraggedDown)
5777 
5778 {
5779   StateDataPtr  prev;
5780   StateDataPtr  next;
5781   Int2          op;
5782 
5783   /*-----------------------------*/
5784   /* Sanity check - can't remove */
5785   /* term from an empty list.    */
5786   /*-----------------------------*/
5787 
5788   if (sdp == NULL) return E2_LIST_NOT_MODIFIED;
5789 
5790   /*------------------------------------*/
5791   /* Detach term from surrounding terms */
5792   /*------------------------------------*/
5793 
5794   next = sdp->next;
5795   prev = sdp->prev;
5796   switch (sdp->group) {
5797     case GROUP_SINGLE:
5798       if (lastDraggedDown)
5799         return E2_LIST_NOT_MODIFIED;
5800       break;
5801     case GROUP_FIRST:
5802       if (next != NULL) {
5803         if (next->group == GROUP_MIDDLE)
5804           next->group = GROUP_FIRST;
5805         else if (next->group == GROUP_LAST)
5806           next->group = GROUP_SINGLE;
5807       }
5808       break;
5809     case GROUP_MIDDLE:
5810       break;
5811     case GROUP_LAST:
5812       if (prev != NULL) {
5813         if (prev->group == GROUP_MIDDLE)
5814           prev->group = GROUP_LAST;
5815         else if (prev->group == GROUP_FIRST)
5816           prev->group = GROUP_SINGLE;
5817       }
5818       break;
5819     default:
5820       break;
5821   }
5822 
5823   /*-------------------------*/
5824   /* Adjust the state of the */
5825   /* surrounding terms.      */
5826   /*-------------------------*/
5827 
5828   sdp->prev = NULL;
5829   sdp->next = NULL;
5830   if (prev != NULL)
5831     prev->next = next;
5832   if (next != NULL)
5833     next->prev = prev;
5834   if (prev == NULL)
5835     pFormInfo->termList = next;
5836   op = ENTREZ_OP_NONE;
5837   switch (sdp->group) {
5838     case GROUP_SINGLE:
5839       if (goingDown) {
5840         if (prev != NULL)
5841           op = prev->below;
5842       } else {
5843         if (next != NULL)
5844           op = next->above;
5845       }
5846       if (prev != NULL)
5847         prev->below = op;
5848       if (next != NULL)
5849         next->above = op;
5850       break;
5851     case GROUP_FIRST:
5852       if (prev != NULL)
5853         op = prev->below;
5854       if (next != NULL)
5855         next->above = op;
5856       break;
5857     case GROUP_MIDDLE:
5858       break;
5859     case GROUP_LAST:
5860       if (next != NULL)
5861         op = next->above;
5862       if (prev != NULL)
5863         prev->below = op;
5864       break;
5865     default:
5866       break;
5867   }
5868 
5869   /*---------------------*/
5870   /* Return successfully */
5871   /*---------------------*/
5872 
5873   return E2_LIST_MODIFIED;
5874 }
5875 
5876 /*====================================================================*/
5877 /*                                                                    */
5878 /*  AddTermToList () - Adds a given term to the given doubly-linked   */
5879 /*                      list of terms, and adjusts the surrounding    */
5880 /*                      terms accordingly.                            */
5881 /*                                                                    */
5882 /*====================================================================*/
5883 
5884 static void AddTermToList (FormInfoPtr pFormInfo, StateDataPtr newTerm, Int2 item, Boolean merge)
5885 
5886 {
5887   StateDataPtr  prev;
5888   StateDataPtr  next;
5889   StateDataPtr  currTerm;
5890   Int2          op;
5891 
5892   /*-------------------------------------*/
5893   /* Add the new term into the term list */
5894   /*-------------------------------------*/
5895 
5896   currTerm = pFormInfo->termList;
5897   if (currTerm == NULL)
5898     pFormInfo->termList = newTerm;
5899   else {
5900     while (item > 1 && currTerm->next != NULL) {
5901       item--;
5902       currTerm = currTerm->next;
5903     }
5904     next = currTerm->next;
5905     prev = currTerm->prev;
5906     currTerm->next = newTerm;
5907     newTerm->next = next;
5908     newTerm->prev = currTerm;
5909     if (next != NULL)
5910       next->prev = newTerm;
5911     op = ENTREZ_OP_NONE;
5912     if (prev != NULL)
5913       op = prev->below;
5914     currTerm->above = op;
5915     newTerm->below = currTerm->below;
5916     currTerm->below = ENTREZ_OP_NONE;
5917     newTerm->above = ENTREZ_OP_NONE;
5918   }
5919 
5920   /*----------------------------------*/
5921   /* Do adding to group, if necessary */
5922   /*----------------------------------*/
5923 
5924   newTerm->group = GROUP_SINGLE;
5925   if (merge && currTerm != NULL) {
5926     switch (currTerm->group) {
5927       case GROUP_SINGLE:
5928         currTerm->group = GROUP_FIRST;
5929         newTerm->group = GROUP_LAST;
5930         break;
5931       case GROUP_FIRST:
5932         newTerm->group = GROUP_MIDDLE;
5933         break;
5934       case GROUP_MIDDLE:
5935         newTerm->group = GROUP_MIDDLE;
5936         break;
5937       case GROUP_LAST:
5938         currTerm->group = GROUP_MIDDLE;
5939         newTerm->group = GROUP_LAST;
5940         break;
5941       default:
5942         break;
5943     }
5944   }
5945 
5946   /*-----------------------------------------*/
5947   /* If it's not in a group, then by default */
5948   /* it's AND'd with the neighboring terms.  */
5949   /*-----------------------------------------*/
5950 
5951   else {
5952     prev = newTerm->prev;
5953     if (prev != NULL) {
5954       prev->below = ENTREZ_OP_AND;
5955       newTerm->above = ENTREZ_OP_AND;
5956     }
5957   }
5958 }
5959 
5960 /*==================================================================*/
5961 /*                                                                  */
5962 /*  ReleaseChosen () - This is the callback function that gets      */
5963 /*                    when the mouse button is released after       */
5964 /*                    dragging a term in the Query Refinement       */
5965 /*                    panel.                                        */
5966 /*                                                                  */
5967 /*==================================================================*/
5968 
5969 static void ReleaseChosen (DoC d, PoinT pt)
5970 
5971 {
5972   Int2          col;
5973   Boolean       goingDown;
5974   Int2          inval;
5975   Int2          item;
5976   Boolean       lastDraggedDown;
5977   Boolean       merge;
5978   Int2          oldItem;
5979   RecT          r;
5980   Int2          row;
5981   RecT          s;
5982   StateDataPtr  sdp;
5983   RecT          sr;
5984   FormInfoPtr   pFormInfo;
5985 
5986   pFormInfo = (FormInfoPtr) GetObjectExtra (d);
5987 
5988   /*---------------------------------------*/
5989   /* Map the current cursor position to an */
5990   /* item in the Query Refinement panel.   */
5991   /*---------------------------------------*/
5992 
5993   MapDocPoint (d, pt, &item, &row, &col, &r);
5994   if (item > 0 && row == 0 && col > 0)
5995     row = 1;
5996 
5997   /*-------------*/
5998   /*-------------*/
5999 
6000   if (pFormInfo->chosenInAboveBox || pFormInfo->chosenInBelowBox) {
6001     LoadRect (&s, r.left, r.top, r.left + 16, r.top + 5);
6002     if (PtInRect (pt, &s)) {
6003       if ((pFormInfo->chosenInAboveBox) && (item == pFormInfo->chosenItem))
6004         FlipOperatorBelow (pFormInfo, pFormInfo->chosenItem - 1);
6005       else if ((pFormInfo->chosenInBelowBox) && (item == pFormInfo->chosenItem - 1))
6006         FlipOperatorBelow (pFormInfo, pFormInfo->chosenItem - 1);
6007     }
6008     LoadRect (&s, r.left, r.bottom - 5, r.left + 16, r.bottom);
6009     if (PtInRect (pt, &s)) {
6010       if ((pFormInfo->chosenInBelowBox) && (item == pFormInfo->chosenItem))
6011         FlipOperatorBelow (pFormInfo, pFormInfo->chosenItem);
6012       else if ((pFormInfo->chosenInAboveBox) && (item == pFormInfo->chosenItem + 1))
6013         FlipOperatorBelow (pFormInfo, pFormInfo->chosenItem);
6014     }
6015     return;
6016   }
6017 
6018   /*-----------------------*/
6019   /*-----------------------*/
6020 
6021   if (pFormInfo->chosenItem > 0) {
6022 
6023     oldItem = pFormInfo->chosenItem;
6024     pFormInfo->chosenItem = 0;
6025     InvertMode ();
6026     FrameChosen (pFormInfo);
6027     Update ();
6028     InvalDocCols (pFormInfo->chosenDoc, oldItem, 1, 2);
6029     Update ();
6030     if (item == oldItem) return;
6031     if (pFormInfo->chosenNumLines < 2) return;
6032 
6033       /*-----------------------------------------------*/
6034     /* Are we dragging the last item 'past' the end? */
6035       /*-----------------------------------------------*/
6036 
6037     lastDraggedDown = FALSE;
6038     if (oldItem == pFormInfo->chosenNumLines && item > pFormInfo->chosenNumLines)
6039       lastDraggedDown = TRUE;
6040 
6041       /*-----------*/
6042       /*-----------*/
6043 
6044     merge = TRUE;
6045     ObjectRect (pFormInfo->chosenDoc, &sr);
6046     InsetRect (&sr, 4, 4);
6047     /*
6048        if (item > pFormInfo->chosenNumLines && PtInRect (pt, &sr))
6049     */
6050     if (item == 0 && PtInRect (pt, &sr)) {
6051       merge = FALSE;
6052       item = INT2_MAX;
6053     }
6054 
6055       /*-------*/
6056       /*-------*/
6057 
6058     if ((item <= 0) || (pFormInfo->termList == NULL))
6059       return;
6060 
6061       /*--------------------------------------*/
6062     /* Are we moving an item down the list? */
6063       /*--------------------------------------*/
6064 
6065     goingDown = FALSE;
6066     if (item > oldItem) {
6067       item--;
6068       goingDown = TRUE;
6069     }
6070 
6071       /*--------------------------------*/
6072     /* Find the item being dragged in */
6073     /* the state list.                */
6074       /*--------------------------------*/
6075 
6076     sdp = pFormInfo->termList;
6077     while (oldItem > 1 && sdp != NULL) {
6078       oldItem--;
6079       sdp = sdp->next;
6080     }
6081 
6082     /*----------------------------------------*/
6083     /* Remove the term from the term list and */
6084     /* then re-add it in it's new position.   */
6085     /*----------------------------------------*/
6086 
6087     if (RemoveTermFromList (pFormInfo, sdp, goingDown, lastDraggedDown) ==
6088         E2_LIST_NOT_MODIFIED) return;
6089 
6090     AddTermToList (pFormInfo, sdp, item, merge);
6091 
6092     /*---------------------------*/
6093     /* Recalculate the new query */
6094     /* and redisplay it.         */
6095     /*---------------------------*/
6096 
6097     ResetClip ();
6098     WatchCursor ();
6099     Update ();
6100     AlphabetizeGroups (pFormInfo);
6101     RepopulateChosen (pFormInfo);
6102     RecalculateChosen (pFormInfo);
6103     ArrowCursor ();
6104   }
6105 
6106   /*------------------------------------*/
6107   /* If the count column was clicked on */
6108   /* then toggle rows state on or off.  */
6109   /*------------------------------------*/
6110 
6111   if ((pFormInfo->chosenClickItem == item) &&
6112       (pFormInfo->chosenClickRow == row)   &&
6113       (pFormInfo->chosenClickCol == col)   &&
6114       (col == 3)) {
6115     inval = item;
6116     sdp = pFormInfo->termList;
6117     while (sdp != NULL && item > 1) {
6118       sdp = sdp->next;
6119       item--;
6120     }
6121     if (sdp == NULL) return;
6122     switch (sdp->state) {
6123       case STATE_OFF:
6124         sdp->state = STATE_ON;
6125         break;
6126       case STATE_ON:
6127         sdp->state = STATE_OFF;
6128         break;
6129       default:
6130         sdp->state = STATE_OFF;
6131         break;
6132     }
6133     ResetClip ();
6134     WatchCursor ();
6135     InvalDocCols (pFormInfo->chosenDoc, inval, 3, 3);
6136     Update ();
6137     RecalculateChosen (pFormInfo);
6138     ArrowCursor ();
6139   }
6140 }
6141 
6142 /*==================================================================*/
6143 /*                                                                  */
6144 /*  InitChosenPanel () -                                            */
6145 /*                                                                  */
6146 /*==================================================================*/
6147 
6148 static void InitChosenPanel (FormInfoPtr pFormInfo)
6149 
6150 {
6151   Entrez2InfoPtr       e2ip;
6152   Entrez2DbInfoPtr     e2db;
6153   Entrez2FieldInfoPtr  e2fd;
6154   Int2                 maxWidth = 0;
6155   RecT                 r;
6156   Char                 str [32];
6157 
6158   SetDocProcs (pFormInfo->chosenDoc, ClickChosen, DragChosen, ReleaseChosen, NULL);
6159   SetDocShade (pFormInfo->chosenDoc, DrawChosenBrackets, NULL, HighlightChosen, NULL);
6160   pFormInfo->chosenNumLines = 0;
6161 
6162   ObjectRect (pFormInfo->chosenDoc, &r);
6163   InsetRect (&r, 4, 4);
6164 
6165   SelectFont (systemFont);
6166   chosenColFmt [2].pixWidth = StringWidth ("0000000") + 10;
6167   chosenColFmt [1].pixWidth = StringWidth ("0000000")  + 10;
6168 
6169   /* more accurate calculation of chosenColFmt [1].pixWidth */
6170 
6171   e2ip = Query_GetInfo ();
6172   if (e2ip != NULL) {
6173     for (e2db = e2ip->db_info; e2db != NULL; e2db = e2db->next) {
6174       for (e2fd = e2db->fields; e2fd != NULL; e2fd = e2fd->next) {
6175         if (e2fd->field_name == NULL || StringLen (e2fd->field_name) > 20) continue;
6176         sprintf (str, " [%s]", e2fd->field_name);
6177         maxWidth = MAX (maxWidth, StringWidth (str));
6178       }
6179     }
6180     chosenColFmt [1].pixWidth = maxWidth  + 10;
6181   }
6182 
6183   chosenColFmt [0].pixWidth = (r.right - r.left) - chosenColFmt [1].pixWidth - chosenColFmt [2].pixWidth;
6184   SetDocAutoAdjust (pFormInfo->chosenDoc, FALSE);
6185 
6186   InvalDocument (pFormInfo->chosenDoc);
6187 }
6188 
6189 /*==================================================================*/
6190 /*                                                                  */
6191 /*  SetupStdQueryGroup () - Create and initialize the Standard      */
6192 /*                          Query Form.                             */
6193 /*                                                                  */
6194 /*==================================================================*/
6195 
6196 static GrouP SetupStdQueryGroup (FormInfoPtr pFormInfo, GrouP mainGroup)
6197 
6198 {
6199   Entrez2DbInfoPtr   e2db;
6200   Entrez2InfoPtr     e2ip;
6201   GrouP              stdQueryGroup;
6202   GrouP              enumlistGroup;
6203   EnumFieldAssocPtr  alist;
6204   Int2               idx;
6205   Int2               db;
6206   Int2               wid;
6207   GrouP              c;
6208   GrouP              j;
6209   GrouP              q1;
6210   GrouP              q2;
6211   GrouP              q3;
6212   PrompT             ppt1;
6213   PrompT             ppt2;
6214   ModeChoice         mc;
6215   ModeIndex          md;
6216   RecT               r;
6217 
6218   /*---------------------------------*/
6219   /* Get info about the DB server(s) */
6220   /*---------------------------------*/
6221 
6222   e2ip = Query_GetInfo ();
6223   if (e2ip == NULL) return NULL;
6224 
6225   /*---------------------------------*/
6226   /* Create the Standard Query Group */
6227   /*---------------------------------*/
6228 
6229   stdQueryGroup = HiddenGroup (mainGroup, -1, 0, NULL);
6230   SetGroupSpacing (stdQueryGroup, 5, 5);
6231 
6232   /*---------------------------------*/
6233   /* Create a group for the pulldown */
6234   /* lists and the accept button.    */
6235   /*---------------------------------*/
6236 
6237   enumlistGroup = HiddenGroup (stdQueryGroup, 0, 2, NULL);
6238   SetGroupSpacing (enumlistGroup, 15, 2);
6239 
6240   /*-------------------------------*/
6241   /* Set up database pulldown list */
6242   /*-------------------------------*/
6243 
6244   StaticPrompt (enumlistGroup, "Database:", 0, 0, programFont, 'l');
6245   q1 = HiddenGroup (enumlistGroup, 0, 0, NULL);
6246   alist = CreateDatabaseAlist (e2ip);
6247   idx = DBGetIDFromName ("PubMed");
6248 
6249   pFormInfo->databasePopup = CreateEnumPopupDialog (q1, TRUE, ChangeDatabase_Callback, alist, (UIEnum) idx, NULL);
6250   SetObjectExtra (pFormInfo->databasePopup, pFormInfo, NULL);
6251   FreeEnumFieldAlist (alist);
6252   pFormInfo->currDb = idx;
6253 
6254   /*-------------------------------*/
6255   /* Set up field pulldown list(s) */
6256   /*-------------------------------*/
6257 
6258   StaticPrompt (enumlistGroup, "Field:", 0, 0, programFont, 'l');
6259   q2 = HiddenGroup (enumlistGroup, 0, 0, NULL);
6260   pFormInfo->fieldsPopup = MemNew (sizeof (PopuP) * (e2ip->db_count + 2));
6261   idx = FieldGetIDFromName (pFormInfo->currDb, "ALL");
6262   for (e2db = e2ip->db_info; e2db != NULL; e2db = e2db->next) {
6263     db = DBGetIDFromName (e2db->db_name);
6264     alist = CreateFieldAlist (e2db);
6265     pFormInfo->fieldsPopup [db] = CreateEnumPopupDialog (q2, TRUE, ChangeField_Callback, alist, (UIEnum) idx, pFormInfo);
6266     FreeEnumFieldAlist (alist);
6267     Hide (pFormInfo->fieldsPopup [db]);
6268   }
6269   pFormInfo->currField = idx;
6270   db = DBGetIDFromName ("PubMed");
6271   Show (pFormInfo->fieldsPopup [db]);
6272 
6273   /*---------------------------*/
6274   /* Set up mode pulldown list */
6275   /*---------------------------*/
6276 
6277   StaticPrompt (enumlistGroup, "Mode:", 0, 0, programFont, 'l');
6278   q3 = HiddenGroup (enumlistGroup, 0, 0, NULL);
6279   for (md = POPUP_MULT; md <= POPUP_UID; md++) {
6280     alist = mode_alists [md];
6281     mc = SELECTION_MODE;
6282     if (md == POPUP_MULT)
6283       mc = AUTOMATIC_MODE;
6284     else if (md == POPUP_AUTO)
6285       mc = TRANSLATE_MODE;
6286     else if (md == POPUP_UID)
6287       mc = LOOKUP_UID_MODE;
6288     pFormInfo->modesPopup [md] = CreateEnumPopupDialog (q3, TRUE, ChangeMode_Callback, alist, (UIEnum) mc, pFormInfo);
6289     Hide (pFormInfo->modesPopup [md]);
6290   }
6291   pFormInfo->currMode = AUTOMATIC_MODE;
6292   md = POPUP_MULT;
6293   Show (pFormInfo->modesPopup [md]);
6294 
6295   /*----------------------*/
6296   /* Set up accept button */
6297   /*----------------------*/
6298 
6299   StaticPrompt (enumlistGroup, "", 0, 0, programFont, 'l');
6300   pFormInfo->acceptButton = DefaultButton (enumlistGroup, "Accept", Accept_Callback);
6301   SetObjectExtra (pFormInfo->acceptButton, pFormInfo, NULL);
6302   Disable (pFormInfo->acceptButton);
6303 
6304   AlignObjects (ALIGN_MIDDLE, (HANDLE) q1, (HANDLE) q2, (HANDLE) q3, (HANDLE) pFormInfo->acceptButton, NULL);
6305 
6306   /*------------------------------*/
6307   /* Create a group to contain:   */
6308   /*                              */
6309   /*    Term entry                */
6310   /*    From/To Range entry       */
6311   /*    Taxonomy 'Lineage' popup  */
6312   /*                              */
6313   /* These are mutually exclusive */
6314   /* and only one of these will   */
6315   /* be visible at a time.        */
6316   /*------------------------------*/
6317 
6318   c = HiddenGroup (stdQueryGroup, 0, 0, NULL);
6319 
6320   GetPosition (pFormInfo->acceptButton, &r);
6321   SelectFont (programFont);
6322   wid = r.right - (StringWidth ("From:") + StringWidth ("To:")) - 30;
6323   SelectFont (systemFont);
6324   wid /= 2 * stdCharWidth;
6325 
6326   pFormInfo->termGroup = HiddenGroup (c, 2, 0, NULL);
6327   StaticPrompt (pFormInfo->termGroup, "Term:", 0, dialogTextHeight, programFont, 'l');
6328   pFormInfo->termText = DialogText (pFormInfo->termGroup, "", 20, TextAction);
6329   SetObjectExtra (pFormInfo->termText, pFormInfo, NULL);
6330 
6331   pFormInfo->rangeGroup = HiddenGroup (c, 4, 0, NULL);
6332   StaticPrompt (pFormInfo->rangeGroup, "From:", 0, dialogTextHeight, programFont, 'l');
6333   pFormInfo->fromText = DialogText (pFormInfo->rangeGroup, "", wid, FromTextAction);
6334   pFormInfo->isValidFrom = FALSE;
6335   SetObjectExtra (pFormInfo->fromText, pFormInfo, NULL);
6336 
6337   StaticPrompt (pFormInfo->rangeGroup, "To:", 0, dialogTextHeight, programFont, 'l');
6338   pFormInfo->toText = DialogText (pFormInfo->rangeGroup, "", wid, ToTextAction);
6339   pFormInfo->isValidTo = FALSE;
6340   SetObjectExtra (pFormInfo->toText, pFormInfo, NULL);
6341   Hide (pFormInfo->rangeGroup);
6342 
6343   pFormInfo->taxLineagePopup = PopupList (c, TRUE, ChangeTaxParents_Callback);
6344   Hide (pFormInfo->taxLineagePopup);
6345   SetObjectExtra (pFormInfo->taxLineagePopup, pFormInfo, NULL);
6346   pFormInfo->taxStrings = NULL;
6347 
6348   /*------------------------------------*/
6349   /* Create the Avail and Chosen panels */
6350   /*------------------------------------*/
6351 
6352   c = HiddenGroup (stdQueryGroup, -1, 0, NULL);
6353   ppt1 = StaticPrompt (c, "Term Selection", 0, 0, programFont, 'c');
6354   pFormInfo->availDoc = DocumentPanel (c, 10 * stdCharWidth, 7 * stdLineHeight);
6355   SetObjectExtra (pFormInfo->availDoc, pFormInfo, NULL);
6356 
6357   ppt2 = StaticPrompt (c, "Query Refinement", 0, 0, programFont, 'c');
6358   j = HiddenGroup (c, 0, 0, NULL);
6359   pFormInfo->chosenDoc = DocumentPanel (j, 10 * stdCharWidth, 7 * stdLineHeight);
6360   SetObjectExtra (pFormInfo->chosenDoc, pFormInfo, NULL);
6361 
6362   /*-------------------*/
6363   /* Align the objects */
6364   /*-------------------*/
6365 
6366   AlignObjects (ALIGN_CENTER, (HANDLE) pFormInfo->taxLineagePopup, (HANDLE) pFormInfo->termGroup, NULL);
6367   AlignObjects (ALIGN_MIDDLE, (HANDLE) pFormInfo->taxLineagePopup, (HANDLE) pFormInfo->termGroup, (HANDLE) pFormInfo->rangeGroup, NULL);
6368   AlignObjects (ALIGN_RIGHT,
6369                 (HANDLE) pFormInfo->acceptButton,
6370                 (HANDLE) pFormInfo->termText,
6371                 (HANDLE) pFormInfo->availDoc, (HANDLE) pFormInfo->chosenDoc, (HANDLE) pFormInfo->toText, (HANDLE) ppt1, (HANDLE) ppt2, NULL);
6372 
6373   /*---------------------------------*/
6374   /* Create a group for the Retrieve */
6375   /* and Reset buttons.              */
6376   /*---------------------------------*/
6377 
6378   c = HiddenGroup (stdQueryGroup, 5, 0, NULL);
6379   SetGroupSpacing (c, 10, 10);
6380 
6381   pFormInfo->retrieveButton = PushButton (c, "Retrieve 000000000 Documents", pFormInfo->retrieveDocsProc);
6382   SetObjectExtra (pFormInfo->retrieveButton, pFormInfo, NULL);
6383   SetTitle (pFormInfo->retrieveButton, "Retrieve 0 Documents");
6384   Disable (pFormInfo->retrieveButton);
6385 
6386   pFormInfo->resetButton = PushButton (c, "Reset", Reset_Callback);
6387   SetObjectExtra (pFormInfo->resetButton, pFormInfo, NULL);
6388 
6389   /*----------------------------------------*/
6390   /* Initialize the Avail and Chosen panels */
6391   /*----------------------------------------*/
6392 
6393   InitChosenPanel (pFormInfo);
6394   InitAvailPanel (pFormInfo);
6395 
6396   /*---------------------*/
6397   /* Return successfully */
6398   /*---------------------*/
6399 
6400   return stdQueryGroup;
6401 }
6402 
6403 /*==================================================================*/
6404 /*                                                                  */
6405 /*  CreateTermlistForm() -                                          */
6406 /*                                                                  */
6407 /*     The object hierarchy is:                                     */
6408 /*                                                                  */
6409 /*        MainWindow                                                */
6410 /*           MainGroup                                              */
6411 /*                                                                  */
6412 /*              PulldownMenus                                       */
6413 /*                                                                  */
6414 /*              StdQueryGroup                                       */
6415 /*                 EnumListGroup                                    */
6416 /*                    DbPopup                                       */
6417 /*                    FieldPopup                                    */
6418 /*                    ModePopup(s)                                  */
6419 /*                    AcceptButton                                  */
6420 /*                 MiscGroup                                        */
6421 /*                    TermDialogText                                */
6422 /*                    FromDialogText                                */
6423 /*                    ToDialogText                                  */
6424 /*                    TaxLineagePopup                               */
6425 /*                 AvailGroup                                       */
6426 /*                    AvailPrompt                                   */
6427 /*                    AvailPanel                                    */
6428 /*                 ChosenGroup                                      */
6429 /*                    ChosenPrompt                                  */
6430 /*                    ChosenPanel                                   */
6431 /*                 ButtonGroup                                      */
6432 /*                    RetrieveButton                                */
6433 /*                    ResetButton                                   */
6434 /*                                                                  */
6435 /*              AdvQueryGroup                                       */
6436 /*                 AdvQueryTextBox                                  */
6437 /*                 ButtonGroup                                      */
6438 /*                    EvaluateButton                                */
6439 /*                    RetrieveButton                                */
6440 /*                    ResetButton                                   */
6441 /*                                                                  */
6442 /*==================================================================*/
6443 
6444 NLM_EXTERN ForM CreateTermlistForm (
6445   Int2 left,
6446   Int2 top,
6447   CharPtr title,
6448   WndActnProc activateCallback,
6449   FormMessageFunc messagesCallback,
6450   E2RetrieveDocsProc retrieveCallback,
6451   E2RetrieveUidProc retrieveUidCallback,
6452   Boolean explodeToggle,
6453   Boolean advancedQueryToggle
6454 )
6455 
6456 {
6457   WindoW       mainWindow;
6458   GrouP        mainGroup;
6459   FormInfoPtr  pFormInfo;
6460 
6461   /*-----------------------------------*/
6462   /* Create a formInfo structure to be */
6463   /* filled in by this function.       */
6464   /*-----------------------------------*/
6465 
6466   pFormInfo = (FormInfoPtr) MemNew (sizeof (FormInfo));
6467   if (pFormInfo == NULL) return NULL;
6468 
6469   /*-----------------------------*/
6470   /* Fill in some default values */
6471   /*-----------------------------*/
6472 
6473   pFormInfo->advQueryLexPos = 0;
6474   pFormInfo->advQueryLexStr = NULL;
6475   pFormInfo->advQueryLexState = LEXSTATE_IDLE;
6476   pFormInfo->advQueryNextToken = NULL;
6477   pFormInfo->form = NULL;
6478   pFormInfo->termList = NULL;
6479 
6480   /*----------------------------*/
6481   /* Create the Main Window and */
6482   /* set up basic callbacks.    */
6483   /*----------------------------*/
6484 
6485   mainWindow = FixedWindow (left, top, -10, -10, title, StdSendCloseWindowMessageProc);
6486   if (mainWindow == NULL) return NULL;
6487 
6488   pFormInfo->formmessage = EditMessage_Callback;
6489   pFormInfo->appmessage = messagesCallback;
6490   pFormInfo->activate = activateCallback;
6491   pFormInfo->retrieveDocsProc = retrieveCallback;
6492   pFormInfo->retrieveUidProc = retrieveUidCallback;
6493   SetActivate (mainWindow, TermListActivate_Callback);
6494 
6495   /*---------------------------------------*/
6496   /* Set up the menus and an overall group */
6497   /* for everything in the termlist window */
6498   /*---------------------------------------*/
6499 
6500   SetupMenus (mainWindow, pFormInfo, explodeToggle, advancedQueryToggle);
6501 
6502   mainGroup = HiddenGroup (mainWindow, 0, 0, NULL);
6503 
6504   pFormInfo->stdQueryGroup = SetupStdQueryGroup (pFormInfo, mainGroup);
6505   pFormInfo->advQueryGroup = SetupAdvQueryGroup (pFormInfo, mainGroup);
6506 
6507   AlignObjects (ALIGN_RIGHT, (HANDLE) pFormInfo->availDoc, (HANDLE) pFormInfo->advQueryText, NULL);
6508 
6509   /*----------------------------------*/
6510   /* Show the advanced query group if */
6511   /* we're in advanced query mode.    */
6512   /*----------------------------------*/
6513 
6514   if (advancedQueryToggle == TRUE)
6515     SafeHide (pFormInfo->stdQueryGroup);
6516   else
6517     SafeHide (pFormInfo->advQueryGroup);
6518 
6519   /*--------------------------------------*/
6520   /* Select the default starting database */
6521   /*--------------------------------------*/
6522 
6523   ChangeDatabase (pFormInfo->databasePopup);
6524 
6525   /*--------------------------------*/
6526   /* Fill in the FormInfo structure */
6527   /*--------------------------------*/
6528 
6529   pFormInfo->form = (ForM) mainWindow;
6530 
6531   /*---------------------*/
6532   /* Return successfully */
6533   /*---------------------*/
6534 
6535   SetObjectExtra ((ForM) mainWindow, (BaseFormPtr) pFormInfo, TermListCleanup_Callback);
6536 
6537   RealizeWindow (mainWindow);
6538   SetWindowTimer (mainWindow, AvailTimerProc);
6539 
6540   return pFormInfo->form;
6541 }
6542 
6543 /*==================================================================*/
6544 /*                                                                  */
6545 /* Query_GetInfo () - Connect to the Entrez2 server and get DB      */
6546 /*                   info -- db names, field names, etc.            */
6547 /*                                                                  */
6548 /*==================================================================*/
6549 
6550 NLM_EXTERN Entrez2InfoPtr Query_GetInfo (void)
6551 
6552 {
6553   Entrez2RequestPtr  e2rq;
6554   Entrez2ReplyPtr    e2ry;
6555   FILE               *fp;
6556   ValNodePtr         head = NULL;
6557   Char               path [PATH_MAX];
6558   CharPtr            str;
6559   ValNodePtr         vnp;
6560 
6561   /*---------------------------------*/
6562   /* Only query the server once, use */
6563   /* stored version afterwards.      */
6564   /*---------------------------------*/
6565 
6566   if (s_masterE2ip != NULL) return s_masterE2ip;
6567 
6568   /*----------------------------------*/
6569   /* Request the data from the server */
6570   /*----------------------------------*/
6571 
6572   e2rq = EntrezCreateGetInfoRequest ();
6573   if (e2rq == NULL) return NULL;
6574 
6575   if (ShowASN () == TRUE)
6576     DisplayEntrezRequest (e2rq);
6577 
6578   e2ry = SpecialEntrezSynchronousQuery (e2rq);
6579   if (e2ry == NULL) return NULL;
6580 
6581   if (ShowASN () == TRUE)
6582     DisplayEntrezReply (e2ry);
6583 
6584   s_masterE2ip = EntrezExtractInfoReply (e2ry);
6585 
6586   Entrez2RequestFree (e2rq);
6587 
6588   /*------------------------------*/
6589   /* Validate EntrezInfo contents */
6590   /*------------------------------*/
6591 
6592   if (! ValidateEntrez2InfoPtr (s_masterE2ip, &head)) {
6593     TmpNam (path);
6594     fp = FileOpen (path, "w");
6595     if (fp != NULL) {
6596       fprintf (fp, "Entrez2Info Validation Errors\n\n");
6597       for (vnp = head; vnp != NULL; vnp = vnp->next) {
6598         str = (CharPtr) vnp->data.ptrvalue;
6599         if (str == NULL) continue;
6600         fprintf (fp, "%s\n", str);
6601       }
6602       FileClose (fp);
6603       LaunchGeneralTextViewer (path, "ValidateEntrez2InfoPtr");
6604     }
6605     FileRemove (path);
6606     ValNodeFreeData (head);
6607   }
6608 
6609   /*---------------------*/
6610   /* Return successfully */
6611   /*---------------------*/
6612 
6613   return s_masterE2ip;
6614 }
6615 
6616 /*==================================================================*/
6617 /*                                                                  */
6618 /*  TermlistToRequestCloseGroup () - Builds a boolean request from  */
6619 /*                           the info in the given TermFormPtr.     */
6620 /*                                                                  */
6621 /*==================================================================*/
6622 
6623 static Boolean TermlistToRequestCloseGroup (FormInfoPtr pFormInfo, Entrez2RequestPtr e2RequestPtr)
6624 
6625 {
6626   Int2                 group;
6627   Int2                 last;
6628   StateDataPtr         sdp;
6629   Boolean              isEmpty = TRUE;
6630   Boolean              doNotExplode;
6631   Boolean              doNotTranslate = FALSE;
6632   CharPtr              rangeStr;
6633   CharPtr              fromTerm;
6634   CharPtr              toTerm;
6635   Entrez2FieldInfoPtr  fieldInfo;
6636   CharPtr              dbName;
6637 
6638   group = 0;
6639   last = 0;
6640   doNotExplode = ! GetStatus (pFormInfo->explodeItem);
6641   sdp = pFormInfo->termList;
6642 
6643   /* Loop through all the terms in the linked list */
6644 
6645   for (sdp = pFormInfo->termList; sdp != NULL; sdp = sdp->next) {
6646 
6647     /* Do not translate if DB is PubMed */
6648     /* and the field is ALL.            */
6649 
6650     fieldInfo = FieldGetInfo (sdp->db, sdp->fld);
6651     dbName = DBGetNameFromID (sdp->db);
6652     
6653     if ((StrICmp(dbName, "PubMed") == 0) && 
6654          (StrICmp(fieldInfo->field_name, "ALL") == 0))
6655       doNotTranslate = doNotExplode; /* doNotTranslate = TRUE; */
6656     else
6657       doNotTranslate = doNotExplode;
6658 
6659     if (sdp->group == GROUP_SINGLE || sdp->group == GROUP_FIRST)
6660       group++;
6661     if (sdp->state == STATE_ON) {
6662       isEmpty = FALSE;
6663 
6664       /* Add opening parens at beginning */
6665 
6666       if (last == 0) {
6667         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_LEFT_PAREN,
6668                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6669                                    doNotExplode, doNotTranslate);
6670         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_LEFT_PAREN,
6671                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6672                                    doNotExplode, doNotTranslate);
6673       }
6674 
6675       /* Put an 'OR' operator between groups */
6676 
6677       else if (last == group) {
6678         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_OR,
6679                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6680                                    doNotExplode, doNotTranslate);
6681       }
6682 
6683       /* Put 'BUTNOT' operator where requested */
6684 
6685       else if (sdp->above == ENTREZ_OP_BUTNOT) {
6686         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_RIGHT_PAREN,
6687                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6688                                    doNotExplode, doNotTranslate);
6689         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_RIGHT_PAREN,
6690                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6691                                    doNotExplode, doNotTranslate);
6692         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_BUTNOT,
6693                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6694                                    doNotExplode, doNotTranslate);
6695         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_LEFT_PAREN,
6696                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6697                                    doNotExplode, doNotTranslate);
6698         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_LEFT_PAREN,
6699                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6700                                    doNotExplode, doNotTranslate);
6701       }
6702 
6703       /* Otherwise default operator is 'AND' */
6704 
6705       else {
6706         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_RIGHT_PAREN,
6707                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6708                                    doNotExplode, doNotTranslate);
6709         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_AND,
6710                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6711                                    doNotExplode, doNotTranslate);
6712         EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_LEFT_PAREN,
6713                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6714                                    doNotExplode, doNotTranslate);
6715       }
6716 
6717       /* Add in the term itself */
6718 
6719       if (sdp->key == NULL) {
6720 
6721         /* If it is a range, then split out the to and from */
6722 
6723         if (StringChr (sdp->term, ':') != 0) {
6724           rangeStr = (CharPtr) MemNew (strlen (sdp->term) + 1);
6725           StringCpy (rangeStr, sdp->term);
6726           fromTerm = StringTokMT(rangeStr, ":", &rangeStr);
6727           toTerm = StringTokMT(rangeStr, ":", &rangeStr);
6728           if ((fromTerm != NULL) && (toTerm != NULL)) {
6729             EntrezAddToBooleanRequest (e2RequestPtr, NULL, 0, sdp->field,
6730                                        fromTerm, NULL, 0, 0, NULL, NULL,
6731                                        doNotExplode, doNotTranslate);
6732             EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_RANGE,
6733                                        NULL, NULL, NULL, 0, 0, NULL, NULL,
6734                                        doNotExplode, doNotTranslate);
6735             EntrezAddToBooleanRequest (e2RequestPtr, NULL, 0, sdp->field,
6736                                        toTerm, NULL, 0, 0, NULL, NULL,
6737                                        doNotExplode, doNotTranslate);
6738           }
6739           MemFree (rangeStr);
6740         }
6741         else
6742           EntrezAddToBooleanRequest (e2RequestPtr, NULL, 0, sdp->field,
6743                                      sdp->term, NULL, 0, 0, NULL, NULL,
6744                                      doNotExplode, doNotTranslate);
6745       } else {
6746         EntrezAddToBooleanRequest (e2RequestPtr, NULL, 0, NULL, NULL,
6747                                    sdp->key, 0, 0, NULL, NULL,
6748                                    doNotExplode, doNotTranslate);
6749         EntrezSetUseHistoryFlag (e2RequestPtr);
6750       }
6751       last = group;
6752     }
6753   }
6754 
6755   if (isEmpty == TRUE) return FALSE;
6756 
6757   /* Add on the closing parens */
6758 
6759   if (group > 0 && last > 0) {
6760     EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_RIGHT_PAREN,
6761                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6762                                    doNotExplode, doNotTranslate);
6763     EntrezAddToBooleanRequest (e2RequestPtr, NULL, ENTREZ_OP_RIGHT_PAREN,
6764                                    NULL, NULL, NULL, 0, 0, NULL, NULL,
6765                                    doNotExplode, doNotTranslate);
6766   }
6767 
6768   /* Return successfully */
6769 
6770   return TRUE;
6771 }
6772 
6773 /*==================================================================*/
6774 /*                                                                  */
6775 /*  Query_FetchUIDs () - Use the linked list of terms stored in     */
6776 /*                      the TermFormPtr to generate a query that    */
6777 /*                      returns all matching UIDs.                  */
6778 /*                                                                  */
6779 /*==================================================================*/
6780 
6781 NLM_EXTERN Entrez2BooleanReplyPtr Query_FetchUIDs (ForM f)
6782 
6783 {
6784   CharPtr                 dbName;
6785   Entrez2RequestPtr       e2RequestPtr;
6786   Entrez2ReplyPtr         e2ReplyPtr;
6787   Entrez2BooleanReplyPtr  e2BooleanPtr;
6788   FormInfoPtr             pFormInfo;
6789 
6790   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
6791 
6792   /*------------------------------------*/
6793   /* Make sure that we have at hand all */
6794   /* the ingredients for the query.     */
6795   /*------------------------------------*/
6796 
6797   if (pFormInfo->termList == NULL || pFormInfo->chosenNumLines < 1 || pFormInfo->termList->db < 0) return 0;
6798 
6799   /*--------------------------------*/
6800   /* Get the name of the current DB */
6801   /*--------------------------------*/
6802 
6803   dbName = DBGetNameFromID (pFormInfo->currDb);
6804   if (StringHasNoText (dbName)) return 0;
6805 
6806   /*---------------------------------*/
6807   /* Create an empty Boolean request */
6808   /*---------------------------------*/
6809 
6810   e2RequestPtr = EntrezCreateBooleanRequest (TRUE, FALSE, dbName, NULL, 0, 0, NULL, 0, 0);
6811   if (e2RequestPtr == NULL) return 0;
6812 
6813   /*------------------------------------*/
6814   /* Convert the linked list of boolean */
6815   /* terms into a boolean request and   */
6816   /* send the request to the server.    */
6817   /*------------------------------------*/
6818 
6819   if (! TermlistToRequestCloseGroup (pFormInfo, e2RequestPtr)) return 0;
6820 
6821   if (ShowASN () == TRUE)
6822     DisplayEntrezRequest (e2RequestPtr);
6823 
6824   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
6825   if (e2ReplyPtr == NULL) return 0;
6826 
6827   if (ShowASN () == TRUE)
6828     DisplayEntrezReply (e2ReplyPtr);
6829 
6830   /*----------------------------------*/
6831   /* Parse the count out of the reply */
6832   /*----------------------------------*/
6833 
6834   e2BooleanPtr = EntrezExtractBooleanReply (e2ReplyPtr);
6835 
6836   /*----------------------------------*/
6837   /* Clean up and return successfully */
6838   /*----------------------------------*/
6839 
6840   Entrez2RequestFree (e2RequestPtr);
6841 
6842   return e2BooleanPtr;
6843 }
6844 
6845 /*==================================================================*/
6846 /*                                                                  */
6847 /*  Query_FetchSeveralCounts () -                                   */
6848 /*                                                                  */
6849 /*==================================================================*/
6850 
6851 NLM_EXTERN Entrez2TermListPtr Query_FetchSeveralCounts (CharPtr dbName, CharPtr fieldName, CharPtr searchStr, Int2 count)
6852 
6853 {
6854   Entrez2RequestPtr   e2RequestPtr;
6855   Entrez2ReplyPtr     e2ReplyPtr;
6856   Entrez2TermListPtr  e2TermListPtr;
6857   Int4                termPos;
6858 
6859   /*-----------------------------------------*/
6860   /* Find the position of the requested term */
6861   /*-----------------------------------------*/
6862 
6863   e2RequestPtr = EntrezCreateGetTermPositionRequest (dbName, fieldName, searchStr);
6864   if (ShowASN () == TRUE)
6865     DisplayEntrezRequest (e2RequestPtr);
6866 
6867   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
6868 
6869   if (ShowASN () == TRUE)
6870     DisplayEntrezReply (e2ReplyPtr);
6871 
6872   if (e2ReplyPtr == NULL) return NULL;
6873 
6874   termPos = EntrezExtractTermPosReply (e2ReplyPtr);
6875 
6876   /*---------------------------------*/
6877   /* Retrieve the requested term and */
6878   /* several following terms.        */
6879   /*---------------------------------*/
6880 
6881   e2RequestPtr = EntrezCreateGetTermListRequest (dbName, fieldName, termPos, count);
6882   if (ShowASN () == TRUE)
6883     DisplayEntrezRequest (e2RequestPtr);
6884 
6885   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
6886 
6887   if (ShowASN () == TRUE)
6888     DisplayEntrezReply (e2ReplyPtr);
6889 
6890   if (e2ReplyPtr == NULL) return NULL;
6891 
6892   e2TermListPtr = EntrezExtractTermListReply (e2ReplyPtr);
6893 
6894   /*---------------------*/
6895   /* Return successfully */
6896   /*---------------------*/
6897 
6898   return e2TermListPtr;
6899 }
6900 
6901 /*==================================================================*/
6902 /*                                                                  */
6903 /*  Query_FetchCount () -                                           */
6904 /*                                                                  */
6905 /*==================================================================*/
6906 
6907 NLM_EXTERN Int4 Query_FetchCount (ForM f)
6908 
6909 {
6910   CharPtr                 dbName;
6911   Int4                    count;
6912   Entrez2RequestPtr       e2RequestPtr;
6913   Entrez2ReplyPtr         e2ReplyPtr;
6914   Entrez2BooleanReplyPtr  e2BooleanPtr;
6915   FormInfoPtr             pFormInfo;
6916 
6917   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
6918 
6919   /*------------------------------------*/
6920   /* Make sure that we have at hand all */
6921   /* the ingredients for the query.     */
6922   /*------------------------------------*/
6923 
6924   if (pFormInfo->termList == NULL || pFormInfo->chosenNumLines < 1 || pFormInfo->termList->db < 0) return 0;
6925 
6926   /*--------------------------------*/
6927   /* Get the name of the current DB */
6928   /*--------------------------------*/
6929 
6930   dbName = DBGetNameFromID (pFormInfo->currDb);
6931   if (StringHasNoText (dbName)) return 0;
6932 
6933   /*---------------------------------*/
6934   /* Create an empty Boolean request */
6935   /*---------------------------------*/
6936 
6937   e2RequestPtr = EntrezCreateBooleanRequest (FALSE, FALSE, dbName, NULL, 0, 0, NULL, 0, 0);
6938   if (e2RequestPtr == NULL) return 0;
6939 
6940   /*------------------------------------*/
6941   /* Convert the linked list of boolean */
6942   /* terms into a boolean request and   */
6943   /* send the request to the server.    */
6944   /*------------------------------------*/
6945 
6946   if (! TermlistToRequestCloseGroup (pFormInfo, e2RequestPtr)) return 0;
6947 
6948   if (ShowASN () == TRUE)
6949     DisplayEntrezRequest (e2RequestPtr);
6950 
6951   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
6952 
6953   if (ShowASN () == TRUE)
6954     DisplayEntrezReply (e2ReplyPtr);
6955 
6956   if (e2ReplyPtr == NULL) return 0;
6957 
6958   /*----------------------------------*/
6959   /* Parse the count out of the reply */
6960   /*----------------------------------*/
6961 
6962   e2BooleanPtr = EntrezExtractBooleanReply (e2ReplyPtr);
6963   if (e2BooleanPtr == NULL) return 0;
6964 
6965   count = e2BooleanPtr->count;
6966 
6967   /*----------------------------------*/
6968   /* Clean up and return successfully */
6969   /*----------------------------------*/
6970 
6971   Entrez2BooleanReplyFree (e2BooleanPtr);
6972   Entrez2RequestFree (e2RequestPtr);
6973 
6974   return count;
6975 }
6976 
6977 /*==================================================================*/
6978 /*                                                                  */
6979 /*  RemoveExtraQuotes () -                                          */
6980 /*                                                                  */
6981 /*==================================================================*/
6982 
6983 static CharPtr RemoveExtraQuotes (CharPtr origString)
6984 
6985 {
6986   Int2     charNum = 0;
6987   Int2     length;
6988   CharPtr  newString;
6989   Int2     newCharNum = 0;
6990 
6991   length = StringLen (origString);
6992   newString = MemNew (length + 1);
6993   for (charNum = 0; charNum < length; charNum++) {
6994     if (origString [charNum] != '"') {
6995       newString [newCharNum] = origString [charNum];
6996       newCharNum++;
6997     }
6998   }
6999 
7000   return newString;
7001 }
7002 
7003 /*==================================================================*/
7004 /*                                                                  */
7005 /*  Query_FetchParsedCount () -                                     */
7006 /*                                                                  */
7007 /*==================================================================*/
7008 
7009 NLM_EXTERN Int4 Query_FetchParsedCount (ForM f)
7010 
7011 {
7012   CharPtr                 dbName;
7013   Entrez2RequestPtr       e2RequestPtr;
7014   Entrez2ReplyPtr         e2ReplyPtr;
7015   Int4                    count;
7016   Entrez2BooleanReplyPtr  e2BooleanPtr;
7017   FormInfoPtr             pFormInfo;
7018   Entrez2BooleanTermPtr   tmpTerm;
7019   StateDataPtr            currentTerm;
7020   Boolean                 found;
7021   ValNodePtr              valNodeTermList;
7022   CharPtr                 cleanedUpTerm;
7023 
7024   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
7025 
7026   /*------------------------------------*/
7027   /* Make sure that we have at hand all */
7028   /* the ingredients for the query.     */
7029   /*------------------------------------*/
7030 
7031   if (pFormInfo->termList == NULL ||
7032       pFormInfo->chosenNumLines < 1 ||
7033       pFormInfo->termList->db < 0)
7034     return -1;
7035 
7036   /*--------------------------------*/
7037   /* Get the name of the current DB */
7038   /*--------------------------------*/
7039 
7040   dbName = DBGetNameFromID (pFormInfo->currDb);
7041   if (StringHasNoText (dbName)) return -1;
7042 
7043   /*---------------------------------*/
7044   /* Create an empty Boolean request */
7045   /*---------------------------------*/
7046 
7047   e2RequestPtr = EntrezCreateBooleanRequest (FALSE, TRUE, dbName, NULL,
7048                                              0, 0, NULL, 0, 0);
7049   if (e2RequestPtr == NULL) return -1;
7050 
7051   /*------------------------------------*/
7052   /* Convert the linked list of boolean */
7053   /* terms into a boolean request and   */
7054   /* send the request to the server.    */
7055   /*------------------------------------*/
7056 
7057   if (! TermlistToRequestCloseGroup (pFormInfo, e2RequestPtr)) return -1;
7058 
7059   if (ShowASN () == TRUE)
7060     DisplayEntrezRequest (e2RequestPtr);
7061 
7062   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
7063 
7064   if (ShowASN () == TRUE)
7065     DisplayEntrezReply (e2ReplyPtr);
7066 
7067   if (e2ReplyPtr == NULL) return -1;
7068 
7069   /*--------------------------------*/
7070   /* Parse the counts for each term */
7071   /* out of the reply.              */
7072   /*--------------------------------*/
7073 
7074   e2BooleanPtr = EntrezExtractBooleanReply (e2ReplyPtr);
7075   if (e2BooleanPtr == NULL) return -1;
7076 
7077   count = e2BooleanPtr->count;
7078 
7079   if (e2BooleanPtr->query != NULL) {
7080     valNodeTermList = e2BooleanPtr->query->exp;
7081 
7082     while (valNodeTermList != NULL) {
7083       if (valNodeTermList->choice == 3) {
7084         tmpTerm = (Entrez2BooleanTermPtr) valNodeTermList->data.ptrvalue;
7085         cleanedUpTerm = RemoveExtraQuotes (tmpTerm->term);
7086         StringCpy (tmpTerm->term, cleanedUpTerm);
7087         currentTerm = pFormInfo->termList;
7088         found = FALSE;
7089         while ((currentTerm != NULL) && (! found)) {
7090           if ((StrICmp (currentTerm->field, tmpTerm->field) == 0) &&
7091               (StrICmp (currentTerm->term, tmpTerm->term) == 0)) {
7092             currentTerm->count = tmpTerm->term_count;
7093             found = TRUE;
7094           }
7095           currentTerm = currentTerm->next;
7096         }
7097       }
7098       valNodeTermList = valNodeTermList->next;
7099     }
7100   }
7101 
7102   /*----------------------------------*/
7103   /* Clean up and return successfully */
7104   /*----------------------------------*/
7105 
7106   Entrez2BooleanReplyFree (e2BooleanPtr);
7107   Entrez2RequestFree (e2RequestPtr);
7108 
7109   return count;
7110 }
7111 
7112 /*==================================================================*/
7113 /*                                                                  */
7114 /*  Query_GetTranslatedCount () -                                   */
7115 /*                                                                  */
7116 /*==================================================================*/
7117 
7118 static Int4 Query_GetTranslatedTermCount (FormInfoPtr pFormInfo, CharPtr dbName, CharPtr fieldName, CharPtr term)
7119 
7120 {
7121   Char                displayStr [256];
7122   Entrez2RequestPtr   e2RequestPtr;
7123   Entrez2ReplyPtr     e2ReplyPtr;
7124   Entrez2TermListPtr  e2TermListPtr;
7125   Int2                row;
7126   Int4                termPos;
7127   Entrez2TermPtr      termPtr;
7128 
7129   /*-----------------------------------------*/
7130   /* Find the position of the requested term */
7131   /*-----------------------------------------*/
7132 
7133   e2RequestPtr = EntrezCreateGetTermPositionRequest (dbName, fieldName, term);
7134 
7135   if (ShowASN () == TRUE)
7136     DisplayEntrezRequest (e2RequestPtr);
7137 
7138   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
7139 
7140   if (ShowASN () == TRUE)
7141     DisplayEntrezReply (e2ReplyPtr);
7142 
7143   if (e2ReplyPtr == NULL) return -1;
7144 
7145   termPos = EntrezExtractTermPosReply (e2ReplyPtr);
7146 
7147   /*---------------------------------*/
7148   /* Retrieve the requested term and */
7149   /* several following terms.        */
7150   /*---------------------------------*/
7151 
7152   e2RequestPtr = EntrezCreateGetTermListRequest (dbName, fieldName, termPos, AVAIL_WINDOW_ROWS);
7153 
7154   if (ShowASN () == TRUE)
7155     DisplayEntrezRequest (e2RequestPtr);
7156 
7157   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
7158 
7159   if (ShowASN () == TRUE)
7160     DisplayEntrezReply (e2ReplyPtr);
7161 
7162   if (e2ReplyPtr == NULL) return -1;
7163 
7164   e2TermListPtr = EntrezExtractTermListReply (e2ReplyPtr);
7165 
7166   if (e2TermListPtr == NULL) return -1;
7167 
7168   pFormInfo->availItem = 0;
7169   pFormInfo->availRow = 0;
7170   Reset (pFormInfo->availDoc);
7171   SetDocCache (pFormInfo->availDoc, NULL, NULL, NULL);
7172   Update ();
7173 
7174   for (row = 1, termPtr = e2TermListPtr->list; row <= AVAIL_WINDOW_ROWS && termPtr != NULL; row++, termPtr = termPtr->next) {
7175     sprintf (displayStr, "%s\t%ld\t%d\n", termPtr->term, (long) (termPtr->count), (int) (termPtr->is_leaf_node ? 1 : 0));
7176     AppendText (pFormInfo->availDoc, displayStr, &availParFmt, availColFmt, systemFont);
7177   }
7178 
7179   InvalDocument (pFormInfo->availDoc);
7180   Update ();
7181 
7182   if (StringICmp (e2TermListPtr->list->term, term) == 0) return e2TermListPtr->list->count;
7183 
7184   return -1;
7185 }
7186 
7187 /*==================================================================*/
7188 /*                                                                  */
7189 /*  Query_TranslateAndAddBoolTerm () -                              */
7190 /*                      Have the server translate a single term     */
7191 /*                      into multiple terms, each with their own    */
7192 /*                      count. Then add each of these terms to the  */
7193 /*                      the termlist (in an OR'd group) and display */
7194 /*                      them.                                       */
7195 /*                                                                  */
7196 /*==================================================================*/
7197 
7198 static Boolean Query_TranslateAndAddBoolTerm (
7199   ForM    f,
7200   Int2    currDb,
7201   Int2    currFld,
7202   CharPtr strs,
7203   Int2    state,
7204   Int4    num
7205 )
7206 
7207 {
7208   StateDataPtr            sdp = NULL;
7209   Entrez2RequestPtr       e2RequestPtr;
7210   Entrez2ReplyPtr         e2ReplyPtr;
7211   Entrez2BooleanReplyPtr  e2BooleanPtr;
7212   CharPtr                 dbName;
7213   Entrez2BooleanTermPtr   tmpTerm;
7214   ValNodePtr              valNodeTermList;
7215   CharPtr                 cleanedUpTerm;
7216   Boolean                 firstTerm;
7217   StateDataPtr            prev = NULL;
7218   CharPtr                 fieldName;
7219   Int2                    fieldId;
7220   Entrez2FieldInfoPtr     fieldInfo;
7221   FormInfoPtr             pFormInfo;
7222   Int2                    nextOperator = ENTREZ_OP_NONE;
7223   Int2                    nextGroup;
7224   Int2                    tmpOp;
7225   Boolean                 allowDuplicates;
7226   Boolean                 doNotTranslate;
7227 
7228   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
7229 
7230   /*-------------------------------------------*/
7231   /* Get the names of the current db and field */
7232   /*-------------------------------------------*/
7233 
7234   dbName = DBGetNameFromID (currDb);
7235   if (StringHasNoText (dbName)) return FALSE;
7236 
7237   fieldInfo = FieldGetInfo (currDb, currFld);
7238   if (fieldInfo == NULL) return FALSE;
7239 
7240   /*------------------------------------------*/
7241   /* Allow duplicates if the DB is PubMed and */
7242   /* the field is All.                        */
7243   /*------------------------------------------*/
7244 
7245   if ((StringICmp (dbName, "PubMed") == 0) &&
7246       (StringICmp (fieldInfo->field_name, "All") == 0))
7247     allowDuplicates = TRUE;
7248   else
7249     allowDuplicates = FALSE;
7250 
7251   /*-----------------------------------*/
7252   /* Create and send a boolean request */
7253   /* to return a translated list       */
7254   /* of terms for the given term.      */
7255   /*-----------------------------------*/
7256 
7257   doNotTranslate = TRUE;
7258   e2RequestPtr = EntrezCreateBooleanRequest (FALSE, TRUE, dbName, NULL, 0, 0, NULL, 0, 0);
7259   EntrezAddToBooleanRequest (e2RequestPtr, strs, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, TRUE, doNotTranslate);
7260   if (ShowASN () == TRUE)
7261     DisplayEntrezRequest (e2RequestPtr);
7262 
7263   e2ReplyPtr = SpecialEntrezSynchronousQuery (e2RequestPtr);
7264 
7265   if (ShowASN () == TRUE)
7266     DisplayEntrezReply (e2ReplyPtr);
7267 
7268   if (e2ReplyPtr == NULL) return FALSE;
7269 
7270   e2BooleanPtr = EntrezExtractBooleanReply (e2ReplyPtr);
7271   if (e2BooleanPtr == NULL) return FALSE;
7272 
7273   if (e2BooleanPtr->query == NULL) return FALSE;
7274 
7275   /*------------------------------------------------*/
7276   /* Parse the resulting terms out of the query and */
7277   /* add them one at a time to the current list of  */
7278   /* terms and to the chosen window.                */
7279   /*------------------------------------------------*/
7280 
7281   valNodeTermList = e2BooleanPtr->query->exp;
7282 
7283   firstTerm = TRUE;
7284   nextGroup = GROUP_SINGLE;
7285   while (valNodeTermList != NULL) {
7286     if (valNodeTermList->choice == TERMLIST_OPERATOR) {
7287       tmpOp = (Int2) valNodeTermList->data.intvalue;
7288       switch (tmpOp) {
7289         case ENTREZ_OP_AND:
7290           if (sdp != NULL) {
7291             if (sdp->group == GROUP_MIDDLE) {
7292               sdp->group = GROUP_LAST;
7293             } else if (sdp->group == GROUP_FIRST) {
7294               sdp->group = GROUP_SINGLE;
7295             }
7296           }
7297           nextOperator = tmpOp;
7298           nextGroup = GROUP_SINGLE;
7299           break;
7300         case ENTREZ_OP_OR:
7301         case ENTREZ_OP_BUTNOT:
7302           nextOperator = tmpOp;
7303           break;
7304         case ENTREZ_OP_LEFT_PAREN:
7305           nextGroup = GROUP_FIRST;
7306           break;
7307         case ENTREZ_OP_RIGHT_PAREN:
7308           break;
7309       }
7310     } else if (valNodeTermList->choice == TERMLIST_TERM) {
7311 
7312       /*---------------------*/
7313       /* Parse the term info */
7314       /*---------------------*/
7315 
7316       tmpTerm = (Entrez2BooleanTermPtr) valNodeTermList->data.ptrvalue;
7317       cleanedUpTerm = RemoveExtraQuotes (tmpTerm->term);
7318       StringCpy (tmpTerm->term, cleanedUpTerm);
7319       if (IsValidFieldName (currDb, tmpTerm->field) == FALSE)
7320         fieldName = FieldGetNameFromMenuName (currDb, tmpTerm->field);
7321       else
7322         fieldName = tmpTerm->field;
7323 
7324       fieldId = -1;
7325       if (StringDoesHaveText (fieldName)) {
7326         fieldId = FieldGetIDFromName (currDb, fieldName);
7327       }
7328 
7329       if (fieldId != -1) {
7330 
7331         /*-----------------------------------*/
7332         /* Replace -1 with actual term count */
7333         /*  Note -- this also creates the    */
7334         /*    desired 'flashing' effect in   */
7335         /*    the termlist window.           */
7336         /*-----------------------------------*/
7337 
7338         tmpTerm->term_count = Query_GetTranslatedTermCount (pFormInfo, dbName, fieldName, tmpTerm->term);
7339 
7340         /*-------------------------------*/
7341         /* Add the term to the term list */
7342         /*-------------------------------*/
7343 
7344         if (NULL != sdp)
7345           prev = sdp;
7346         sdp = CreateTerm (f, currDb, fieldId, tmpTerm->term, state,
7347                           tmpTerm->term_count, allowDuplicates);
7348         if (NULL == sdp) {
7349           valNodeTermList = valNodeTermList->next;
7350           sdp = prev;
7351           continue;
7352         }
7353 
7354         /*-------------------------------*/
7355         /* Make all the translated terms */
7356         /* an or'd group of terms.       */
7357         /*-------------------------------*/
7358 
7359         switch (nextGroup) {
7360           case GROUP_SINGLE:
7361             sdp->group = GROUP_SINGLE;
7362             break;
7363           case GROUP_FIRST:
7364             sdp->group = GROUP_FIRST;
7365             nextGroup = GROUP_MIDDLE;
7366             break;
7367           case GROUP_MIDDLE:
7368             sdp->group = GROUP_MIDDLE;
7369             break;
7370           case GROUP_LAST:
7371             sdp->group = GROUP_LAST;
7372             break;
7373         }
7374 
7375         if (firstTerm == TRUE) {
7376           prev = sdp->prev;
7377           if (prev != NULL) {
7378             sdp->above = ENTREZ_OP_AND;
7379             prev->below = ENTREZ_OP_AND;
7380           }
7381           firstTerm = FALSE;
7382         } else {
7383           prev = sdp->prev;
7384           sdp->above = nextOperator;
7385           prev->below = nextOperator;
7386         }
7387 
7388         /*--------------------------------------*/
7389         /* Display the term in the chosen panel */
7390         /*--------------------------------------*/
7391 
7392         DisplayTerm (pFormInfo, tmpTerm->term, fieldName, tmpTerm->term_count);
7393 
7394       } else {
7395         if (StringDoesHaveText (tmpTerm->field)) {
7396           Message (MSG_POSTERR, "Bad field name %s ignored in expanded query", tmpTerm->field);
7397         } else {
7398           Message (MSG_POSTERR, "Empty field name ignored in expanded query");
7399         }
7400       }
7401     }
7402     valNodeTermList = valNodeTermList->next;
7403   }
7404 
7405   /*---------------------------*/
7406   /* Mark the last term as the */
7407   /* last in the group.        */
7408   /*---------------------------*/
7409 
7410   if (NULL != sdp)
7411     if (sdp->group != GROUP_SINGLE) {
7412       if (sdp->group == GROUP_FIRST)
7413         sdp->group = GROUP_SINGLE;
7414       else
7415         sdp->group = GROUP_LAST;
7416     }
7417 
7418   /*--------------------------------*/
7419   /* Flatten out nested 'OR' groups */
7420   /*       (A OR (B OR C))          */
7421   /*   becomes                      */
7422   /*       (A OR B OR C)            */
7423   /*--------------------------------*/
7424 
7425   sdp = pFormInfo->termList;
7426   while (sdp != NULL) {
7427     if ((sdp->group == GROUP_FIRST) &&
7428         (sdp->above == ENTREZ_OP_OR) &&
7429         (sdp->below == ENTREZ_OP_OR))
7430       sdp->group = GROUP_MIDDLE;
7431     sdp = sdp->next;
7432   }
7433 
7434   /*------------------------*/
7435   /* Recalculate and redraw */
7436   /*------------------------*/
7437 
7438   AlphabetizeGroups (pFormInfo);
7439   RepopulateChosen (pFormInfo);
7440   RecalculateChosen (pFormInfo);
7441 
7442   /*---------------------*/
7443   /* Return successfully */
7444   /*---------------------*/
7445 
7446   return TRUE;
7447 }
7448 
7449 /*==================================================================*/
7450 /*                                                                  */
7451 /*  RefineUIDs () -                                                 */
7452 /*                                                                  */
7453 /*==================================================================*/
7454 
7455 NLM_EXTERN Boolean RefineUIDs (ForM f, CharPtr term, Int4 num, Int4Ptr uids, Int2 db)
7456 
7457 {
7458   CharPtr            advQueryStr;
7459   EnumFieldAssocPtr  alist;
7460   Entrez2InfoPtr     e2ip;
7461   FormInfoPtr        pFormInfo;
7462   Char               str [64];
7463   WindoW             tempPort;
7464 
7465   pFormInfo = (FormInfoPtr) GetObjectExtra (f);
7466 
7467   /*-------------------------------*/
7468   /* Set the query window settings */
7469   /*-------------------------------*/
7470 
7471   e2ip = Query_GetInfo ();
7472   if (e2ip == NULL) return FALSE;
7473 
7474   alist = CreateDatabaseAlist (e2ip);
7475   if (pFormInfo->currDb != db) {
7476     SetEnumPopup (pFormInfo->databasePopup, alist, (UIEnum) db);
7477     ChangeDatabase (pFormInfo->databasePopup);
7478   } else
7479     DoResetAvail (pFormInfo, TRUE);
7480 
7481   SafeSetTitle (pFormInfo->termText, "");
7482   SafeSetTitle (pFormInfo->fromText, "");
7483   SafeSetTitle (pFormInfo->toText, "");
7484   SafeDisable (pFormInfo->acceptButton);
7485   if (StringHasNoText (term))
7486     term = "*Current_Documents";
7487   if (term [0] == '*')
7488     term++;
7489   StringCpy (str, "*");
7490   StringNCpy (str + 1, term, sizeof (str) - 3);
7491 
7492   /*-----------------------------------*/
7493   /* Add the term to the current query */
7494   /* in the query window.              */
7495   /*-----------------------------------*/
7496 
7497   tempPort = SavePort (pFormInfo->chosenDoc);
7498   Query_AddUidsTerm (pFormInfo->form, str, num, uids, db);
7499   RecalculateChosen (pFormInfo);
7500   RestorePort (tempPort);
7501 
7502   if (! GetStatus (pFormInfo->advancedQueryItem)) {
7503     Show (pFormInfo->termText);
7504     Select (pFormInfo->termText);
7505   } else {
7506     advQueryStr = Query_ConvertToString (pFormInfo->form);
7507     SetAdvancedText (pFormInfo->advQueryText, advQueryStr);
7508     MemFree (advQueryStr);
7509     SafeShow (pFormInfo->advQueryGroup);
7510   }
7511 
7512   /*---------------------*/
7513   /* Return successfully */
7514   /*---------------------*/
7515 
7516   return TRUE;
7517 }
7518 
7519 

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.