NCBI C Toolkit Cross Reference

C/desktop/dlgutil2.c


  1 /*   dlgutil2.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:  dlgutil2.c
 27 *
 28 * Author:  Jonathan Kans
 29 *
 30 * Version Creation Date:   1/22/95
 31 *
 32 * $Revision: 6.211 $
 33 *
 34 * File Description: 
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 * Date     Name        Description of modification
 39 * -------  ----------  -----------------------------------------------------
 40 *
 41 *
 42 * ==========================================================================
 43 */
 44 
 45 #include <dlogutil.h>
 46 #include <document.h>
 47 #include <gather.h>
 48 #include <subutil.h>
 49 #include <objfdef.h>
 50 #include <gbfeat.h>
 51 #include <gbftdef.h>
 52 #include <utilpub.h>
 53 #include <objfeat.h>
 54 #include <objseq.h>
 55 #include <toasn3.h>
 56 #include <explore.h>
 57 #include <findrepl.h>
 58 #ifdef WIN_MOTIF
 59 #include <netscape.h>
 60 #endif
 61 #define NLM_GENERATED_CODE_PROTO
 62 #include <objmacro.h>
 63 #include <macroapi.h>
 64 
 65 typedef struct datepage {
 66   DIALOG_MESSAGE_BLOCK
 67   TexT          year;
 68   PopuP         year_popup;
 69   Int4          start_year;
 70   Int4          num_years;
 71   PopuP         month;
 72   TexT          day;
 73 } DatePage, PNTR DatePagePtr;
 74 
 75 extern CharPtr SaveStringFromTextAndStripNewlines (TexT t)
 76 
 77 {
 78   Char     ch;
 79   size_t   len;
 80   CharPtr  ptr;
 81   CharPtr  str;
 82 
 83   len = TextLength (t);
 84   if (len > 0) {
 85     str = MemNew (len + 1);
 86     if (str != NULL) {
 87       GetTitle (t, str, len + 1);
 88       ptr = str;
 89       ch = *ptr;
 90       while (ch != '\0') {
 91         if (ch < ' ') {
 92           *ptr = ' ';
 93         }
 94         ptr++;
 95         ch = *ptr;
 96       }
 97       TrimSpacesAroundString (str);
 98       if (StringHasNoText (str)) {
 99         str = MemFree (str);
100       }
101       return str;
102     } else {
103       return NULL;
104     }
105   } else {
106     return NULL;
107   }
108 }
109 
110 
111 extern CharPtr StripNewlines (CharPtr str)
112 
113 {
114   Char     ch;
115   size_t   len;
116   CharPtr  ptr;
117 
118   if (str == NULL) return str;
119   len = StringLen (str);
120   if (len > 0) {
121     ptr = str;
122     ch = *ptr;
123     while (ch != '\0') {
124       if (ch < ' ') {
125         *ptr = ' ';
126       }
127       ptr++;
128       ch = *ptr;
129     }
130     TrimSpacesAroundString (str);
131     if (StringHasNoText (str)) {
132       str = MemFree (str);
133     }
134   } else {
135     str = MemFree (str);
136   }
137   return str;
138 }
139 
140 
141 extern void NewlinesToTildes (CharPtr str)
142 
143 {
144   Uchar    ch;
145   CharPtr  ptr;
146 
147   if (StringHasNoText (str)) return;
148   ptr = str;
149   ch = *ptr;
150   while (ch != '\0') {
151     if (ch < ' ') {
152       *ptr = '~';
153     }
154     ptr++;
155     ch = *ptr;
156   }
157 }
158 
159 
160 static void DatePtrToDatePage (DialoG d, Pointer data)
161 
162 {
163   DatePtr      dp;
164   DatePagePtr  dpp;
165   Int2         day;
166   Char         str [32];
167   Int2         year, val;
168 
169 
170   dpp = (DatePagePtr) GetObjectExtra (d);
171   dp = (DatePtr) data;
172   if (dpp != NULL) {
173     if (dp == NULL || dp->data[0] != 1) {
174       SafeSetValue (dpp->month, 1);
175       SafeSetTitle (dpp->day, "");
176       SafeSetTitle (dpp->year, "");
177       SafeSetValue (dpp->year_popup, 1);
178     } else {
179       /* set month */
180       SetEnumPopup (dpp->month, months_alist, (UIEnum) dp->data [2]);
181       /* set day */
182       day = (Int2) dp->data [3];
183       if (day > 0 && day <= 31) {
184         sprintf (str, "%d", (int) day);
185         SafeSetTitle (dpp->day, str);
186       } else {
187         SafeSetTitle (dpp->day, "");
188       }
189       /* set year */
190       year = (Int2) dp->data [1];
191       if (year > 0) {
192         if (dpp->year_popup == NULL) {
193           sprintf (str, "%d", (int) (year + 1900));
194           SafeSetTitle (dpp->year, str);
195         } else {
196           val = year + 1900 - dpp->start_year + 1;
197           if (val < 1 || val >= dpp->num_years) {
198             sprintf (str, "%d", (int) (year + 1900));
199             SafeSetTitle (dpp->year, str);
200             dpp->year_popup = NULL;
201             Show (dpp->year);
202           } else {
203             SetValue (dpp->year_popup, val);
204           }
205         }
206       } else {
207         if (dpp->year_popup == NULL) {
208           SafeSetTitle (dpp->year, "");
209         } else {
210           SetValue (dpp->year_popup, 1);
211         }
212       }
213     }
214   }
215 }
216 
217 static Pointer DatePageToDatePtr (DialoG d)
218 
219 {
220   DatePtr      dp;
221   DatePagePtr  dpp;
222   Int2         day;
223   UIEnum       month;
224   Char         str [32];
225   Int2         year = 0;
226 
227   dp = NULL;
228   dpp = (DatePagePtr) GetObjectExtra (d);
229   if (dpp != NULL) {
230     dp = DateNew ();
231     if (dp != NULL) {
232       dp->data [0] = 1;
233       /* get year value */
234       if (dpp->year_popup != NULL) {
235         year = GetValue (dpp->year_popup);
236         if (year > 0) {
237           year += dpp->start_year - 1;
238         } else {
239           dp = DateFree (dp);
240           return NULL;
241         }
242       } else {
243         GetTitle (dpp->year, str, sizeof (str));
244         if (! StringHasNoText (str)) {
245           StrToInt (str, &year);
246         }
247       }
248       if (year >= 1900) {
249         dp->data [1] = (Uint1) (year - 1900);
250       } else {
251         dp = DateFree (dp);
252         return dp;
253       }
254       /* get month value */
255       if (GetEnumPopup (dpp->month, months_alist, &month)) {
256         dp->data [2] = (Uint1) month;
257       } else {
258         dp = DateFree (dp);
259         return dp;
260       }
261       /* get day value */
262       GetTitle (dpp->day, str, sizeof (str));
263       StrToInt (str, &day);
264       dp->data [3] = (Uint1) day;
265     }
266   }
267   return (Pointer) dp;
268 }
269 
270 extern DialoG CreateDateDialogEx (GrouP prnt, CharPtr title, Int4 start_year, Int4 num_years)
271 
272 {
273   DatePagePtr  dpp;
274   GrouP        f;
275   GrouP        m;
276   GrouP        p;
277   GrouP        s;
278   GrouP        year_grp;
279   Char         year_buf[15];
280   Int4         i;
281 
282   p = HiddenGroup (prnt, 1, 0, NULL);
283   SetGroupSpacing (p, 10, 10);
284 
285   dpp = (DatePagePtr) MemNew (sizeof (DatePage));
286   if (dpp) {
287 
288     SetObjectExtra (p, dpp, StdCleanupExtraProc);
289     dpp->dialog = (DialoG) p;
290     dpp->todialog = DatePtrToDatePage;
291     dpp->fromdialog = DatePageToDatePtr;
292     dpp->testdialog = NULL;
293 
294     dpp->start_year = start_year;
295     dpp->num_years = num_years;
296 
297     if (title != NULL && title [0] != '\0') {
298       s = NormalGroup (p, 0, -2, title, systemFont, NULL);
299     } else {
300       s = HiddenGroup (p, 0, -2, NULL);
301     }
302     m = HiddenGroup (s, -1, 0, NULL);
303     /*
304     SetGroupSpacing (m, 10, 10);
305     */
306 
307     f = HiddenGroup (m, -6, 0, NULL);
308     StaticPrompt (f, "Month", 0, popupMenuHeight, programFont, 'l');
309     dpp->month = PopupList (f, TRUE, NULL);
310     InitEnumPopup (dpp->month, months_alist, NULL);
311     SetValue (dpp->month, 1);
312     StaticPrompt (f, "Day", 0, dialogTextHeight, programFont, 'l');
313     dpp->day = DialogText (f, "", 4, NULL);
314     StaticPrompt (f, "Year", 0, dialogTextHeight, programFont, 'l');
315     year_grp = HiddenGroup (f, 0, 0, NULL);
316     if (start_year > 0 && num_years > -1) {
317       dpp->year_popup = PopupList (year_grp, TRUE, NULL);
318       for (i = 0; i < num_years; i++) {
319         sprintf (year_buf, "%d", start_year + i);
320         PopupItem (dpp->year_popup, year_buf);
321       }
322     }
323     dpp->year = DialogText (year_grp, "", 6, NULL);
324     if (dpp->year_popup != NULL) {
325       SafeHide (dpp->year);
326     }
327     AlignObjects (ALIGN_CENTER, (HANDLE)dpp->year, (HANDLE)dpp->year_popup, NULL);
328   }
329 
330   return (DialoG) p;
331 }
332 
333 
334 extern DialoG CreateDateDialog (GrouP prnt, CharPtr title)
335 
336 {
337   return CreateDateDialogEx (prnt, title, -1, 0);
338 }
339 
340 
341 typedef struct featcit {
342   DIALOG_MESSAGE_BLOCK
343   DoC         citdoc;
344   ValNodePtr  pubset;
345 } FeatCitPage, PNTR FeatCitPagePtr;
346 
347 static ParData cofParFmt = {FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0};
348 static ColData cofColFmt = {0, 0, 0, 0, NULL, 'l', TRUE, FALSE, FALSE, FALSE, TRUE};
349 
350 static ParData cofeParFmt = {TRUE, FALSE, FALSE, FALSE, FALSE, 0, 0};
351 static ColData cofeColFmt = {0, 0, 0, 0, NULL, 'l', TRUE, FALSE, FALSE, FALSE, TRUE};
352 
353 static Uint1 diamondSym [] = {
354   0x00, 0x10, 0x38, 0x7C, 0x38, 0x10, 0x00, 0x00
355 };
356 
357 static void DrawCitOnFeat (DoC d, RectPtr r, Int2 item, Int2 firstLine)
358 
359 {
360   Int2  lineHeight;
361   RecT  rct;
362 
363   if (d != NULL && r != NULL && item > 0 && firstLine == 0) {
364     if (item == 1) return; /* citonfeattxt or citonfeathdr explanatory text */
365     GetItemParams (d, item, NULL, NULL, NULL, &lineHeight, NULL);
366     rct = *r;
367     rct.left += 1;
368     rct.right = rct.left + 7;
369     rct.top += (lineHeight - 7) / 2;
370     rct.bottom = rct.top + 7;
371     CopyBits (&rct, diamondSym);
372     /*
373     x = r->left + 1;
374     y = r->top + lineHeight / 2;
375     MoveTo (x, y);
376     LineTo (x + 5, y);
377     */
378   }
379 }
380 
381 static int LIBCALLBACK CompareStrings (VoidPtr ptr1, VoidPtr ptr2)
382 
383 {
384   CharPtr  str1;
385   CharPtr  str2;
386 
387   if (ptr1 != NULL && ptr2 != NULL) {
388     str1 = *((CharPtr PNTR) ptr1);
389     str2 = *((CharPtr PNTR) ptr2);
390     if (str1 != NULL && str2 != NULL) {
391       return StringICmp (str1, str2);
392     } else {
393       return 0;
394     }
395   } else {
396     return 0;
397   }
398 }
399 
400 static CharPtr citonfeattxt =
401 "Press 'Edit Citations' to attach publications to this feature. \
402 Publications must first be added to the record. For biological \
403 justification, and not to credit the sequencer, create publication \
404 with the 'Cites a feature on the sequence' scope.\n";
405 
406 static CharPtr citonfeathdr =
407 "Press 'Edit Citations' to change publications.\n\n";
408 
409 static void PubsetPtrToFeatCitPage (DialoG d, Pointer data)
410 
411 {
412   Int2            count;
413   FeatCitPagePtr  fpp;
414   Int2            i;
415   Char            label [128];
416   ObjMgrPtr       omp;
417   ObjMgrTypePtr   omtp;
418   ValNodePtr      ppr;
419   ValNodePtr      psp;
420   RecT            r;
421   CharPtr         PNTR strs;
422 
423   fpp = (FeatCitPagePtr) GetObjectExtra (d);
424   psp = (ValNodePtr) data;
425   if (fpp != NULL) {
426     Reset (fpp->citdoc);
427     fpp->pubset = PubSetFree (fpp->pubset);
428     fpp->pubset = AsnIoMemCopy (data,
429                                 (AsnReadFunc) PubSetAsnRead,
430                                 (AsnWriteFunc) PubSetAsnWrite);
431     SetDocAutoAdjust (fpp->citdoc, FALSE);
432     ObjectRect (fpp->citdoc, &r);
433     InsetRect (&r, 4, 4);
434     cofColFmt.pixWidth = r.right - r.left;
435     cofColFmt.pixInset = 10;
436     omp = ObjMgrGet ();
437     if (omp == NULL) return;
438     omtp = ObjMgrTypeFind (omp, OBJ_SEQFEAT_CIT, NULL, NULL);
439     if (omtp == NULL || omtp->labelfunc == NULL) return;
440     if (psp != NULL && psp->data.ptrvalue != NULL) {
441       count = 0;
442       for (ppr = psp->data.ptrvalue; ppr != NULL; ppr = ppr->next) {
443         count++;
444       }
445       if (count > 0) {
446         strs = MemNew (sizeof (CharPtr) * (size_t) (count + 1));
447         if (strs != NULL) {
448           i = 0;
449           for (ppr = psp->data.ptrvalue; ppr != NULL; ppr = ppr->next) {
450             (*(omtp->labelfunc)) (ppr, label, 127, OM_LABEL_CONTENT);
451             strs [i] = StringSave (label);
452             i++;
453           }
454           HeapSort (strs, count, sizeof (CharPtr), CompareStrings);
455           AppendText (fpp->citdoc, citonfeathdr, &cofParFmt, NULL, programFont);
456           for (i = 0; i < count; i++) {
457             AppendText (fpp->citdoc, strs [i],
458                         &cofParFmt, &cofColFmt, programFont);
459           }
460           for (i = 0; i < count; i++) {
461             strs [i] = MemFree (strs [i]);
462           }
463           MemFree (strs);
464         } else {
465           AppendText (fpp->citdoc, citonfeattxt, &cofParFmt, NULL, programFont);
466         }
467       }
468     } else {
469       AppendText (fpp->citdoc, citonfeattxt, &cofParFmt, NULL, programFont);
470     }
471     SetDocShade (fpp->citdoc, DrawCitOnFeat, NULL, NULL, NULL);
472     UpdateDocument (fpp->citdoc, 0, 0);
473   }
474 }
475 
476 static Pointer FeatCitPageToPubsetPtr (DialoG d)
477 
478 {
479   FeatCitPagePtr  fpp;
480   ValNodePtr      psp;
481 
482   psp = NULL;
483   fpp = (FeatCitPagePtr) GetObjectExtra (d);
484   if (fpp != NULL) {
485     psp = AsnIoMemCopy (fpp->pubset,
486                         (AsnReadFunc) PubSetAsnRead,
487                         (AsnWriteFunc) PubSetAsnWrite);
488   }
489   return (Pointer) psp;
490 }
491 
492 static void CleanupCitOnFeatProc (GraphiC g, VoidPtr data)
493 
494 {
495   FeatCitPagePtr  fpp;
496 
497   fpp = (FeatCitPagePtr) data;
498   if (fpp != NULL) {
499     PubSetFree (fpp->pubset);
500   }
501   MemFree (data);
502 }
503 
504 static DialoG CreateCitOnFeatDialog (GrouP h, CharPtr title)
505 
506 {
507   FeatCitPagePtr  fpp;
508   Int2            lineHeight;
509   GrouP           m;
510   GrouP           p;
511   GrouP           s;
512 
513   p = HiddenGroup (h, 1, 0, NULL);
514   SetGroupSpacing (p, 10, 10);
515 
516   fpp = (FeatCitPagePtr) MemNew (sizeof (FeatCitPage));
517   if (fpp != NULL) {
518 
519     SetObjectExtra (p, fpp, CleanupCitOnFeatProc);
520     fpp->dialog = (DialoG) p;
521     fpp->todialog = PubsetPtrToFeatCitPage;
522     fpp->fromdialog = FeatCitPageToPubsetPtr;
523     fpp->testdialog = NULL;
524 
525     if (title != NULL && title [0] != '\0') {
526       s = NormalGroup (p, 0, -2, title, systemFont, NULL);
527     } else {
528       s = HiddenGroup (p, 0, -2, NULL);
529     }
530     m = HiddenGroup (s, -1, 0, NULL);
531     /*
532     SetGroupSpacing (m, 10, 10);
533     */
534 
535     SelectFont (programFont);
536     lineHeight = LineHeight ();
537     SelectFont (systemFont);
538     cofParFmt.minHeight = lineHeight + 2;
539     StaticPrompt (m, "Citations on Feature", 25 * stdCharWidth, 0, programFont, 'c');
540     fpp->citdoc = DocumentPanel (m, 25 * stdCharWidth, 5 * cofParFmt.minHeight);
541     SetObjectExtra (fpp->citdoc, fpp, NULL);
542     SetDocAutoAdjust (fpp->citdoc, FALSE);
543     fpp->pubset = NULL;
544   }
545 
546   return (DialoG) p;
547 }
548 
549 typedef struct citlist {
550   Uint2    entityID;
551   Uint4    itemID;
552   Uint2    itemtype;
553   CharPtr  label;
554 } CitListData, PNTR CitListDataPtr;
555 
556 typedef struct featcitedit {
557   DIALOG_MESSAGE_BLOCK
558   DoC             allcitdoc;
559   Int2            clickedItem;
560   Int2            clickedRow;
561   Int2            numitems;
562   Int2            lineheight;
563   Int2            index;
564   BoolPtr         chosen;
565   ValNodePtr      citlist;
566   ValNodePtr      psp;
567   ObjMgrPtr       omp;
568   Int2            entityID;
569 } FeatCitEdit, PNTR FeatCitEditPtr;
570 
571 static void CleanupFeatCitForm (GraphiC g, VoidPtr data)
572 
573 {
574   FeatCitEditPtr  fcep;
575 
576   fcep = (FeatCitEditPtr) data;
577   if (fcep != NULL) {
578     MemFree (fcep->chosen);
579   }
580   MemFree (data);
581 }
582 
583 static void DrawFeatCit (DoC d, RectPtr r, Int2 item, Int2 firstLine)
584 
585 {
586   FeatCitEditPtr  fcep;
587   RecT            rct;
588 
589   fcep = (FeatCitEditPtr) GetObjectExtra (d);
590   if (fcep != NULL && r != NULL && item > 0 && firstLine == 0) {
591     rct = *r;
592     rct.left += 1;
593     rct.right = rct.left + fcep->lineheight;
594     rct.bottom = rct.top + (rct.right - rct.left);
595     FrameRect (&rct);
596     if (item > 0 && item <= fcep->numitems) {
597       if (fcep->chosen != NULL && fcep->chosen [item - 1]) {
598         MoveTo (rct.left, rct.top);
599         LineTo (rct.right - 1, rct.bottom - 1);
600         MoveTo (rct.left, rct.bottom - 1);
601         LineTo (rct.right - 1, rct.top);
602       }
603     }
604   }
605 }
606 
607 static void ClickFeatCit (DoC d, PoinT pt)
608 
609 {
610 }
611 
612 static void ReleaseFeatCit (DoC d, PoinT pt)
613 
614 {
615   Int2            col;
616   FeatCitEditPtr  fcep;
617   Int2            item;
618   RecT            rct;
619   Int2            row;
620 
621   fcep = (FeatCitEditPtr) GetObjectExtra (d);
622   if (fcep != NULL && fcep->chosen != NULL) {
623     MapDocPoint (d, pt, &item, &row, &col, &rct);
624     rct.left += 1;
625     rct.right = rct.left + fcep->lineheight;
626     rct.bottom = rct.top + (rct.right - rct.left);
627     if (row == 1 && col == 1 && item > 0 && item <= fcep->numitems && PtInRect (pt, &rct)) {
628       if (fcep->chosen [item - 1]) {
629         fcep->chosen [item - 1] = FALSE;
630       } else {
631         fcep->chosen [item - 1] = TRUE;
632       }
633       InsetRect (&rct, -1, -1);
634       InvalRect (&rct);
635       Update ();
636     }
637   }
638 }
639 
640 static Boolean GatherAllCits (GatherContextPtr gcp)
641 
642 {
643   CitListDataPtr  cldp;
644   FeatCitEditPtr  fcep;
645   Char            label [128];
646   ObjMgrTypePtr   omtp;
647   PubdescPtr      pdp;
648   ValNodePtr      sdp;
649   SeqFeatPtr      sfp;
650   ValNodePtr      vnp;
651 
652   if (gcp == NULL) return TRUE;
653   fcep = (FeatCitEditPtr) gcp->userdata;
654   if (fcep == NULL) return TRUE;
655   label [0] = '\0';
656   pdp = NULL;
657   if (gcp->thistype == OBJ_SEQDESC) {
658     sdp = (ValNodePtr) gcp->thisitem;
659     if (sdp == NULL || sdp->choice != Seq_descr_pub) return TRUE;
660     pdp = sdp->data.ptrvalue;
661   } else if (gcp->thistype == OBJ_SEQFEAT) {
662     sfp = (SeqFeatPtr) gcp->thisitem;
663     if (sfp == NULL || sfp->data.choice != SEQFEAT_PUB) return TRUE;
664     pdp = sfp->data.value.ptrvalue;
665   } else return TRUE;
666   if (pdp == NULL) return TRUE;
667   omtp = ObjMgrTypeFind (fcep->omp, gcp->thistype, NULL, NULL);
668   if (omtp == NULL || omtp->labelfunc == NULL) return TRUE;
669   (*(omtp->labelfunc)) (gcp->thisitem, label, 127, OM_LABEL_CONTENT);
670   cldp = (CitListDataPtr) MemNew (sizeof (CitListData));
671   if (cldp != NULL) {
672     vnp = ValNodeNew (fcep->citlist);
673     if (fcep->citlist == NULL) {
674       fcep->citlist = vnp;
675     }
676     if (vnp != NULL) {
677       vnp->data.ptrvalue = cldp;
678       cldp->entityID = gcp->entityID;
679       cldp->itemID = gcp->itemID;
680       cldp->itemtype = gcp->thistype;
681       cldp->label = StringSave (label);
682       (fcep->numitems)++;
683     } else {
684       MemFree (cldp);
685       return TRUE;
686     }
687   }
688   return TRUE;
689 }
690 
691 static Boolean PrintCitOnFeatItem (GatherContextPtr gcp)
692 
693 {
694   CharPtr  PNTR  rsultp;
695   ValNodePtr     sdp;
696   SeqFeatPtr     sfp;
697   Boolean        success;
698 
699   rsultp = (CharPtr PNTR) gcp->userdata;
700   if (rsultp != NULL) {
701     success = FALSE;
702     switch (gcp->thistype) {
703       case OBJ_SEQDESC :
704         sdp = (ValNodePtr) gcp->thisitem;
705         if (sdp->data.ptrvalue != NULL) {
706           success = StdFormatPrint ((Pointer) sdp, (AsnWriteFunc) SeqDescAsnWrite,
707                                     "StdSeqDesc", spop);
708         } else {
709           *rsultp = StringSave ("Empty Descriptor\n");
710           success = TRUE;
711         }
712         break;
713       case OBJ_SEQFEAT :
714         sfp = (SeqFeatPtr) gcp->thisitem;
715         if (sfp != NULL && (sfp->data.choice == 10 || sfp->data.value.ptrvalue != NULL)) {
716           success = StdFormatPrint ((Pointer) sfp, (AsnWriteFunc) SeqFeatAsnWrite,
717                                     "StdSeqFeat", spop);
718         } else {
719           *rsultp = StringSave ("Empty Feature\n");
720           success = TRUE;
721         }
722         break;
723       default :
724         break;
725     }
726     if (success) {
727       if (spop->ptr != NULL && *((CharPtr) (spop->ptr)) != '\0') {
728         *rsultp = spop->ptr;
729         spop->ptr = NULL;
730       } else {
731         *rsultp = StringSave ("Empty Data\n");
732       }
733     } else {
734       *rsultp = StringSave ("Data Failure\n");
735     }
736   }
737   return TRUE;
738 }
739 
740 static CharPtr CitOnFeatPrintProc (DoC doc, Int2 item, Pointer data)
741 
742 {
743   unsigned int  entityID;
744   unsigned int  itemID;
745   unsigned int  itemtype;
746   CharPtr       rsult;
747   CharPtr       str;
748 
749   rsult = NULL;
750   if (data != NULL) {
751     str = (CharPtr) data;
752     if (sscanf (str, "%u %u %u", &entityID, &itemID, &itemtype) == 3) {
753       GatherItem ((Uint2) entityID, (Uint2) itemID, (Uint2) itemtype,
754                   (Pointer) &rsult, PrintCitOnFeatItem);
755     }
756   } else {
757     rsult = StringSave ("Null Data\n");
758   }
759   return rsult;
760 }
761 
762 static int LIBCALLBACK CompareCitList (VoidPtr ptr1, VoidPtr ptr2)
763 
764 {
765   CitListDataPtr  cldp1;
766   CitListDataPtr  cldp2;
767   CharPtr         str1;
768   CharPtr         str2;
769 
770   if (ptr1 != NULL && ptr2 != NULL) {
771     cldp1 = (CitListDataPtr) ptr1;
772     cldp2 = (CitListDataPtr) ptr2;
773     if (cldp1 != NULL && cldp2 != NULL) {
774       str1 = cldp1->label;
775       str2 = cldp2->label;
776       if (str1 != NULL && str2 != NULL) {
777         return StringICmp (str1, str2);
778       } else {
779         return 0;
780       }
781     } else {
782       return 0;
783     }
784   } else {
785     return 0;
786   }
787 }
788 
789 static Boolean MakeMinimalCitOnFeatItem (GatherContextPtr gcp)
790 
791 {
792   PubdescPtr  pdp;
793   ValNodePtr  ppr;
794   ValNodePtr  sdp;
795   SeqFeatPtr  sfp;
796   ValNodePtr  vnp;
797   ValNodePtr  PNTR  vnpp;
798 
799   vnpp = (ValNodePtr PNTR) gcp->userdata;
800   if (vnpp != NULL) {
801     pdp = NULL;
802     switch (gcp->thistype) {
803       case OBJ_SEQDESC :
804         sdp = (ValNodePtr) gcp->thisitem;
805         if (sdp->data.ptrvalue != NULL) {
806           pdp = (PubdescPtr) sdp->data.ptrvalue;
807         }
808         break;
809       case OBJ_SEQFEAT :
810         sfp = (SeqFeatPtr) gcp->thisitem;
811         if (sfp != NULL && (sfp->data.choice == 10 || sfp->data.value.ptrvalue != NULL)) {
812           pdp = (PubdescPtr) sfp->data.value.ptrvalue;
813         }
814         break;
815       default :
816         break;
817     }
818     if (pdp != NULL) {
819       ppr = NULL;
820       vnp = ValNodeNew (NULL);
821       if (vnp != NULL) {
822         vnp->choice = PUB_Equiv;
823         vnp->data.ptrvalue = pdp->pub;
824         ppr = MinimizePub (vnp);
825         ValNodeFree (vnp);
826       }
827       vnp = ValNodeNew (*vnpp);
828       if (*vnpp == NULL) {
829         *vnpp = vnp;
830       }
831       if (vnp != NULL) {
832         vnp->choice = PUB_Equiv;
833         vnp->data.ptrvalue = ppr;
834       }
835     }
836   }
837   return TRUE;
838 }
839 
840 static Boolean MatchMinimalCits (GatherContextPtr gcp)
841 
842 {
843   FeatCitEditPtr  fcep;
844   PubdescPtr      pdp;
845   ValNodePtr      ppr;
846   ValNodePtr      sdp;
847   SeqFeatPtr      sfp;
848   ValNodePtr      vnp;
849 
850   fcep = (FeatCitEditPtr) gcp->userdata;
851   if (fcep != NULL) {
852     pdp = NULL;
853     switch (gcp->thistype) {
854       case OBJ_SEQDESC :
855         sdp = (ValNodePtr) gcp->thisitem;
856         if (sdp->data.ptrvalue != NULL) {
857           pdp = (PubdescPtr) sdp->data.ptrvalue;
858         }
859         break;
860       case OBJ_SEQFEAT :
861         sfp = (SeqFeatPtr) gcp->thisitem;
862         if (sfp != NULL && (sfp->data.choice == 10 || sfp->data.value.ptrvalue != NULL)) {
863           pdp = (PubdescPtr) sfp->data.value.ptrvalue;
864         }
865         break;
866       default :
867         break;
868     }
869     if (pdp != NULL && fcep->psp != NULL) {
870       vnp = ValNodeNew (NULL);
871       if (vnp != NULL) {
872         vnp->choice = PUB_Equiv;
873         vnp->data.ptrvalue = pdp->pub;
874         for (ppr = fcep->psp->data.ptrvalue; ppr != NULL; ppr = ppr->next) {
875           if (PubLabelMatch (vnp, ppr) == 0) {
876             fcep->chosen [fcep->index] = TRUE;
877           }
878         }
879         ValNodeFree (vnp);
880       }
881     }
882   }
883   return TRUE;
884 }
885 
886 static void CitListToDialog (DialoG d, Pointer userdata)
887 {
888   FeatCitEditPtr  fcep;
889   CitListDataPtr  cldp;
890   CitListDataPtr  cldpp;
891   Int2            count;
892   GatherScope     gs;
893   Int2            i;
894   Int2            j;
895   Char            last [128];
896   CharPtr         ptr;
897   RecT            r;
898   Char            str [34];
899   ValNodePtr      vnp;
900 
901   fcep = (FeatCitEditPtr) GetObjectExtra (d);
902   if (fcep == NULL)
903   {
904     return;
905   }
906   Reset (fcep->allcitdoc);
907   
908   fcep->citlist = ValNodeFree (fcep->citlist);
909   fcep->numitems = 0;
910   fcep->chosen = MemFree (fcep->chosen);
911   
912   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
913   MemSet ((Pointer) (gs.ignore), (int) (TRUE), (size_t) (OBJ_MAX * sizeof (Boolean)));
914   gs.ignore [OBJ_SEQDESC] = FALSE;
915   gs.ignore [OBJ_SEQANNOT] = FALSE;
916   gs.ignore [OBJ_SEQFEAT] = FALSE;
917   gs.seglevels = 1;
918   GatherEntity (fcep->entityID, (Pointer) fcep, GatherAllCits, &gs);
919   count = fcep->numitems;
920   cldpp = (CitListDataPtr) MemNew (sizeof (CitListData) * (size_t) (count + 1));
921   if (cldpp != NULL) {
922     for (i = 0, vnp = fcep->citlist; i < count && vnp != NULL; i++, vnp = vnp->next) {
923       cldp = vnp->data.ptrvalue;
924       if (cldp != NULL) {
925         cldpp [i] = *cldp;
926         cldp->label = NULL;
927       }
928     }
929     fcep->citlist = ValNodeFreeData (fcep->citlist);
930     HeapSort (cldpp, count, sizeof (CitListData), CompareCitList);
931     last [0] = '\0';
932     ObjectRect (fcep->allcitdoc, &r);
933     InsetRect (&r, 4, 4);
934     cofeColFmt.pixWidth = r.right - r.left;
935     cofeColFmt.pixInset = 20;
936     fcep->numitems = 0;
937     fcep->chosen = MemNew (sizeof (Boolean) * (size_t) (count + 1));
938 
939     fcep->psp = (ValNodePtr) userdata;
940     for (i = 0, j = 0; i < count; i++) {
941       cldp = &(cldpp [i]);
942       if (cldp != NULL) {
943         if (last == NULL || StringCmp (cldp->label, last) != 0) {
944           sprintf (str, "%d %d %d", (int) cldp->entityID,
945                    (int) cldp->itemID, (int) cldp->itemtype);
946           ptr = StringSave (str);
947           (fcep->numitems)++;
948           AppendItem (fcep->allcitdoc, CitOnFeatPrintProc, (Pointer) ptr,
949                       TRUE, 5, &cofeParFmt, &cofeColFmt, programFont);
950           if (fcep->chosen != NULL) {
951             fcep->index = j;
952             GatherItem ((Uint2) cldp->entityID, (Uint2) cldp->itemID,
953                         (Uint2) cldp->itemtype, (Pointer) fcep, MatchMinimalCits);
954           }
955           j++;
956         }
957         StringNCpy_0 (last, cldp->label, sizeof (last));
958         cldpp [i].label = MemFree (cldpp [i].label);
959       }
960     }
961     fcep->psp = NULL;
962   }
963 }
964 
965 static Pointer DialogToMinimizedCitList (DialoG d)
966 {
967   FeatCitEditPtr  fcep;
968   Pointer         data;
969   unsigned int    entityID;
970   Int2            i;
971   unsigned int    itemID;
972   unsigned int    itemtype;
973   Int2            numItems;
974   ValNodePtr      ppr = NULL, psp = NULL;
975   CharPtr         str;
976   
977   fcep = (FeatCitEditPtr) GetObjectExtra (d);
978   if (fcep == NULL)
979   {
980     return NULL;
981   }
982   
983   if (fcep->chosen != NULL) {
984     GetDocParams (fcep->allcitdoc, &numItems, NULL);
985     for (i = 1; i <= numItems; i++) {
986       if (fcep->chosen [i - 1]) {
987         GetItemParams (fcep->allcitdoc, i, NULL, NULL, NULL, NULL, &data);
988         if (data != NULL) {
989           str = (CharPtr) data;
990           if (sscanf (str, "%u %u %u", &entityID, &itemID, &itemtype) == 3) {
991             GatherItem ((Uint2) entityID, (Uint2) itemID, (Uint2) itemtype,
992                         (Pointer) &ppr, MakeMinimalCitOnFeatItem);
993           }
994         }
995       }
996     }
997   }
998  
999   if (ppr != NULL)
1000   {
1001     psp = ValNodeNew (NULL);
1002     if (psp != NULL) {
1003       psp->choice = 1;
1004       psp->data.ptrvalue = ppr;
1005     }
1006   }
1007   return psp;
1008 }
1009 
1010 extern DialoG FeatCitEditDialog (GrouP parent, Uint2 entityID)
1011 {
1012   FeatCitEditPtr  fcep;
1013   GrouP           p;
1014   
1015   fcep = (FeatCitEditPtr) MemNew (sizeof (FeatCitEdit));
1016   if (fcep == NULL)
1017   {
1018     return NULL;
1019   }
1020 
1021   p = HiddenGroup (parent, -1, 0, NULL);
1022   SetObjectExtra (p, fcep, CleanupFeatCitForm);
1023 
1024   fcep->dialog = (DialoG) p;
1025   fcep->todialog = CitListToDialog;
1026   fcep->fromdialog = DialogToMinimizedCitList;
1027   fcep->dialogmessage = NULL;
1028   fcep->testdialog = NULL;
1029 
1030   fcep->entityID = entityID;
1031   fcep->omp = ObjMgrGet ();
1032   fcep->numitems = 0;
1033 
1034   fcep->allcitdoc = DocumentPanel (p, 25 * stdCharWidth, 15 * stdLineHeight);
1035   SetObjectExtra (fcep->allcitdoc, fcep, NULL);
1036   SetDocProcs (fcep->allcitdoc, ClickFeatCit, NULL, ReleaseFeatCit, NULL);
1037   SetDocShade (fcep->allcitdoc, DrawFeatCit, NULL, NULL, NULL);
1038   
1039   SelectFont (programFont);
1040   fcep->lineheight = LineHeight ();
1041   SelectFont (systemFont);
1042 
1043   return (DialoG) p;
1044 }
1045 
1046 typedef struct featcitationform
1047 {
1048   FeatureFormPtr ffp;
1049   DialoG         citation_list;
1050    
1051 } FeatCitationFormData, PNTR FeatCitationFormPtr;
1052 
1053 static void AcceptFeatCit (ButtoN b)
1054 
1055 {
1056   FeatCitationFormPtr  fcfp;
1057   FeatureFormPtr       ffp;
1058   ValNodePtr           psp = NULL;
1059 
1060   fcfp = (FeatCitationFormPtr) GetObjectExtra (b);
1061   if (fcfp == NULL)
1062   {
1063     return;
1064   }
1065   
1066   psp = DialogToPointer (fcfp->citation_list);
1067   ffp = (FeatureFormPtr) fcfp->ffp;
1068   if (ffp != NULL) {
1069     PointerToDialog (ffp->featcits, (Pointer) psp);
1070     PubSetFree (psp);
1071   }
1072   Remove (ParentWindow (b));
1073 }
1074 
1075 static void EditFeatCitsProc (ButtoN b)
1076 
1077 {
1078   ButtoN          btn;
1079   GrouP           c;
1080   FeatCitationFormPtr  fcfp;
1081   FeatureFormPtr  ffp;
1082   WindoW          w;
1083   ValNodePtr      psp;
1084 
1085   ffp = (FeatureFormPtr) GetObjectExtra (b);
1086   if (ffp == NULL)
1087   {
1088     return;
1089   }
1090   fcfp = (FeatCitationFormPtr) MemNew (sizeof (FeatCitationFormData));
1091   if (fcfp == NULL) 
1092   {
1093     return;
1094   }
1095 
1096   WatchCursor ();
1097   Update ();
1098   w = MovableModalWindow (-50, -33, -10, -10, "Citations", NULL);
1099   SetObjectExtra (w, fcfp, StdCleanupExtraProc);
1100   
1101   fcfp->ffp = ffp;
1102   fcfp->citation_list = FeatCitEditDialog (w, ffp->input_entityID);
1103 
1104   c = HiddenGroup (w, 4, 0, NULL);
1105   SetGroupSpacing (c, 10, 3);
1106   btn = PushButton (c, "Accept", AcceptFeatCit);
1107   SetObjectExtra (btn, fcfp, NULL);
1108   PushButton (c, "Cancel", StdCancelButtonProc);
1109   AlignObjects (ALIGN_CENTER, (HANDLE) fcfp->citation_list, (HANDLE) c, NULL);
1110   RealizeWindow (w);
1111   
1112   psp = DialogToPointer (ffp->featcits);
1113   PointerToDialog (fcfp->citation_list, psp);
1114   PubSetFree (psp);
1115 
1116   Show (w);
1117   Select (w);
1118   ArrowCursor ();
1119   Update ();
1120 }
1121 
1122 static void ChangeGenePopupOrList (Handle gene)
1123 
1124 {
1125   FeatureFormPtr  ffp;
1126   Int2            val;
1127 
1128   ffp = (FeatureFormPtr) GetObjectExtra (gene);
1129   if (ffp != NULL) {
1130     val = GetValue (ffp->gene);
1131     if (val == 1) {
1132       SafeHide (ffp->newGeneGrp);
1133       SafeHide (ffp->editGeneBtn);
1134     } else if (val == 2) {
1135       SafeHide (ffp->editGeneBtn);
1136       SafeShow (ffp->newGeneGrp);
1137     } else {
1138       SafeHide (ffp->newGeneGrp);
1139       SafeShow (ffp->editGeneBtn);
1140     }
1141   }
1142 }
1143 
1144 static void ChangeSubGroup (VoidPtr data, Int2 newval, Int2 oldval)
1145 
1146 {
1147   FeatureFormPtr  ffp;
1148 
1149   ffp = (FeatureFormPtr) data;
1150   if (ffp != NULL) {
1151     if (ffp->commonPage >= 0 && ffp->commonPage <= 6) {
1152       SafeHide (ffp->commonSubGrp [ffp->commonPage]);
1153     }
1154     ffp->commonPage = newval;
1155     if (ffp->commonPage >= 0 && ffp->commonPage <= 6) {
1156       SafeShow (ffp->commonSubGrp [ffp->commonPage]);
1157     }
1158   }
1159 }
1160 
1161 typedef struct fieldpage {
1162   DIALOG_MESSAGE_BLOCK
1163   Int2               numfields;
1164   CharPtr            PNTR fields;
1165   TexT               PNTR values;
1166   ButtoN             PNTR boxes;
1167 } FieldPage, PNTR FieldPagePtr;
1168 
1169 
1170 static Boolean ShouldSuppressGBQual(Uint1 subtype, CharPtr qual_name)
1171 {
1172   if (StringHasNoText (qual_name)) {
1173     return FALSE;
1174   }
1175 
1176   /* always suppress experiment and inference quals */
1177   if (StringCmp (qual_name, "experiment") == 0 || StringCmp (qual_name, "inference") == 0) {
1178     return TRUE;
1179   }
1180   
1181   if (subtype == FEATDEF_ncRNA) {
1182     if (StringCmp (qual_name, "product") == 0
1183         || StringCmp (qual_name, "ncRNA_class") == 0) {
1184       return TRUE;
1185     }
1186   } else if (subtype == FEATDEF_tmRNA) {
1187     if (StringCmp (qual_name, "product") == 0
1188         || StringCmp (qual_name, "tag_peptide") == 0) {
1189       return TRUE;
1190     }
1191   } else if (subtype == FEATDEF_otherRNA) {
1192     if (StringCmp (qual_name, "product") == 0) {
1193       return TRUE;
1194     }
1195   }
1196   return FALSE;
1197 }
1198     
1199 
1200 static Boolean ShouldBeAGBQual (Uint1 subtype, Int2 qual, Boolean allowProductGBQual)
1201 
1202 {
1203   if (qual < 0) return FALSE;
1204   if (allowProductGBQual && qual == GBQUAL_product) return TRUE;
1205   if (qual == GBQUAL_citation ||
1206       qual == GBQUAL_db_xref ||
1207       qual == GBQUAL_evidence ||
1208       qual == GBQUAL_exception ||
1209       qual == GBQUAL_gene ||
1210       qual == GBQUAL_gene_synonym ||
1211       qual == GBQUAL_insertion_seq ||
1212       qual == GBQUAL_label ||
1213       qual == GBQUAL_locus_tag ||
1214       qual == GBQUAL_note ||
1215       qual == GBQUAL_partial ||
1216       qual == GBQUAL_product ||
1217       qual == GBQUAL_pseudo ||
1218       qual == GBQUAL_rpt_unit ||
1219       qual == GBQUAL_transposon ||
1220       qual == GBQUAL_experiment ||
1221       qual == GBQUAL_trans_splicing ||
1222       qual == GBQUAL_ribosomal_slippage ||
1223       qual == GBQUAL_inference) {
1224     return FALSE;
1225   }
1226   if (qual == GBQUAL_map && subtype != FEATDEF_ANY && subtype != FEATDEF_repeat_region && subtype != FEATDEF_gap) return FALSE;
1227   if (qual == GBQUAL_operon && subtype != FEATDEF_ANY && subtype != FEATDEF_operon) return FALSE;
1228   if (Nlm_GetAppProperty ("SequinUseEMBLFeatures") == NULL) {
1229     if (qual == GBQUAL_usedin) {
1230       return FALSE;
1231     }
1232   }
1233 
1234   if (qual > -1 && ShouldSuppressGBQual (subtype, ParFlat_GBQual_names [qual].name)) {
1235     return FALSE;
1236   }
1237 
1238   return TRUE;
1239 }
1240 
1241 static CharPtr TrimCommasAndAtSignsAroundGBString (CharPtr str)
1242 
1243 {
1244   Uchar    ch;  /* to use 8bit characters in multibyte languages */
1245   CharPtr  dst;
1246   CharPtr  ptr;
1247 
1248   if (str != NULL && str [0] != '\0') {
1249     dst = str;
1250     ptr = str;
1251     ch = *ptr;
1252     while (ch != '\0' && (ch < ' ' || ch == '{' || ch == ',')) {
1253       ptr++;
1254       ch = *ptr;
1255     }
1256     while (ch != '\0') {
1257       *dst = ch;
1258       dst++;
1259       ptr++;
1260       ch = *ptr;
1261     }
1262     *dst = '\0';
1263     dst = NULL;
1264     ptr = str;
1265     ch = *ptr;
1266     while (ch != '\0') {
1267       if (ch != '}' && ch != ',') {
1268         dst = NULL;
1269       } else if (dst == NULL) {
1270         dst = ptr;
1271       }
1272       ptr++;
1273       ch = *ptr;
1274     }
1275     if (dst != NULL) {
1276       *dst = '\0';
1277     }
1278   }
1279   return str;
1280 }
1281 
1282 static CharPtr CombineSplitGBQual (CharPtr origval, CharPtr newval)
1283 
1284 {
1285   size_t   len;
1286   CharPtr  str = NULL;
1287 
1288   if (StringStr (origval, newval) != NULL) return origval;
1289   len = StringLen (origval) + StringLen (newval) + 5;
1290   str = MemNew (sizeof (Char) * len);
1291   if (str == NULL) return origval;
1292   TrimCommasAndAtSignsAroundGBString (origval);
1293   TrimCommasAndAtSignsAroundGBString (newval);
1294   StringCpy (str, "{");
1295   StringCat (str, origval);
1296   StringCat (str, ",");
1297   StringCat (str, newval);
1298   StringCat (str, "}");
1299   /* free original string, knowing return value will replace it */
1300   MemFree (origval);
1301   return str;
1302 }
1303 
1304 static void CombineTitle (TexT t, CharPtr val)
1305 
1306 {
1307   CharPtr  str;
1308 
1309   if (t == NULL || StringHasNoText (val)) return;
1310   str = SaveStringFromText (t);
1311   if (StringDoesHaveText (str)) {
1312     str = CombineSplitGBQual (str, val);
1313     SetTitle (t, str);
1314   } else {
1315     SetTitle (t, val);
1316   }
1317   MemFree (str);
1318 }
1319 
1320 static void GBQualPtrToFieldPage (DialoG d, Pointer data)
1321 
1322 {
1323   Char          empty [4];
1324   FieldPagePtr  fpf;
1325   Int2          i;
1326   GBQualPtr     list;
1327 
1328   fpf = (FieldPagePtr) GetObjectExtra (d);
1329   list = (GBQualPtr) data;
1330   if (fpf != NULL) {
1331     while (list != NULL) {
1332       if (list->qual != NULL && list->val != NULL) {
1333         for (i = 0; i < fpf->numfields; i++) {
1334           if (StringICmp (list->qual, fpf->fields [i]) == 0) {
1335             if (fpf->values [i] != NULL) {
1336               if (*(list->val) == '\0') {
1337                 empty [0] = '"';
1338                 empty [1] = '"';
1339                 empty [2] = '\0';
1340                 SetTitle (fpf->values [i], empty);
1341               } else if (StringICmp (list->qual, "rpt_type") == 0 ||
1342                          StringICmp (list->qual, "rpt_unit") == 0 ||
1343                          StringICmp (list->qual, "rpt_unit_range") == 0 ||
1344                          StringICmp (list->qual, "rpt_unit_seq") == 0 ||
1345                          StringICmp (list->qual, "replace") == 0 ||
1346                          StringICmp (list->qual, "compare") == 0 ||
1347                          StringICmp (list->qual, "old_locus_tag") == 0 ||
1348                          StringICmp (list->qual, "usedin") == 0) {
1349                 CombineTitle (fpf->values [i], list->val);
1350               } else {
1351                 SetTitle (fpf->values [i], list->val);
1352               }
1353             } else if (fpf->boxes [i] != NULL) {
1354               SetStatus (fpf->boxes [i], TRUE);
1355             }
1356           }
1357         }
1358       }
1359       list = list->next;
1360     }
1361   }
1362 }
1363 
1364 extern void SeqFeatPtrToFieldPage (DialoG d, SeqFeatPtr sfp);
1365 extern void SeqFeatPtrToFieldPage (DialoG d, SeqFeatPtr sfp)
1366 
1367 {
1368   /*
1369   FieldPagePtr  fpf;
1370   Int2          i;
1371 
1372   fpf = (FieldPagePtr) GetObjectExtra (d);
1373   if (fpf != NULL && sfp != NULL) {
1374         for (i = 0; i < fpf->numfields; i++) {
1375           if (StringICmp ("exception", fpf->fields [i]) == 0) {
1376             if (fpf->values [i] != NULL) {
1377               if (sfp->except_text == NULL || *(sfp->except_text) == '\0') {
1378                 SetTitle (fpf->values [i], "");
1379               } else {
1380                 SetTitle (fpf->values [i], sfp->except_text);
1381               }
1382             }
1383           } else if (StringICmp ("pseudo", fpf->fields [i]) == 0) {
1384             if (fpf->boxes [i] != NULL && (! GetStatus (fpf->boxes [i]))) {
1385               SetStatus (fpf->boxes [i], sfp->pseudo);
1386             }
1387           }
1388         }
1389   }
1390   */
1391 
1392 }
1393 
1394 static Pointer FieldPageToGBQualPtr (DialoG d)
1395 
1396 {
1397   FieldPagePtr  fpf;
1398   GBQualPtr     gbq;
1399   GBQualPtr     gbqlast;
1400   GBQualPtr     head;
1401   Int2          i;
1402 
1403   head = NULL;
1404   fpf = (FieldPagePtr) GetObjectExtra (d);
1405   if (fpf != NULL) {
1406     gbq = NULL;
1407     gbqlast = NULL;
1408     for (i = 0; i < fpf->numfields; i++) {
1409       if (fpf->fields [i] == NULL ||
1410           StringHasNoText (fpf->fields [i]) ||
1411           (fpf->values [i] == NULL && fpf->boxes [i] ==NULL) ||
1412           (fpf->values [i] != NULL && TextHasNoText (fpf->values [i]))) {
1413       } else if (fpf->boxes [i] != NULL && (! GetStatus (fpf->boxes [i]))) {
1414       } else {
1415         gbq = GBQualNew ();
1416         if (gbqlast == NULL) {
1417           head = gbq;
1418         } else {
1419           gbqlast->next = gbq;
1420         }
1421         gbqlast = gbq;
1422         if (gbq != NULL) {
1423           gbq->qual = StringSave (fpf->fields [i]);
1424           if (fpf->values [i] != NULL) {
1425             gbq->val = SaveStringFromText (fpf->values [i]);
1426           } else {
1427             gbq->val = StringSave ("");
1428           }
1429         }
1430       }
1431     }
1432   }
1433   return (Pointer) head;
1434 }
1435 
1436 static void CleanupFieldsPage (GraphiC g, VoidPtr data)
1437 
1438 {
1439   FieldPagePtr  fpf;
1440   Int2          i;
1441 
1442   fpf = (FieldPagePtr) data;
1443   if (fpf != NULL) {
1444     if (fpf->fields != NULL) {
1445       for (i = 0; i < fpf->numfields; i++) {
1446         MemFree (fpf->fields [i]);
1447       }
1448     }
1449     MemFree (fpf->fields);
1450     MemFree (fpf->values);
1451     MemFree (fpf->boxes);
1452   }
1453   MemFree (data);
1454 }
1455 
1456 #define LEGAL_FEATURE    1
1457 #define ILLEGAL_FEATURE  2
1458 
1459 extern DialoG CreateImportFields (GrouP h, CharPtr name, SeqFeatPtr sfp, Boolean allowProductGBQual)
1460 
1461 {
1462   FieldPagePtr    fpf;
1463   GrouP           g;
1464   GBQualPtr       gbq;
1465   Boolean         hasillegal;
1466   Int2            i;
1467   ImpFeatPtr      imp;
1468   Int2            index;
1469   Boolean         is_gap = FALSE;
1470   Int2            j;
1471   Int2            max;
1472   Int2            num;
1473   GrouP           p;
1474   PrompT          ppt;
1475   Int2            qual;
1476   Int2            seen [ParFlat_TOTAL_GBQUAL];
1477   SematicFeatPtr  sefp;
1478   Char            str [64];
1479   Int2            wid;
1480 
1481   p = HiddenGroup (h, 1, 0, NULL);
1482   fpf = (FieldPagePtr) MemNew (sizeof (FieldPage));
1483   if (fpf != NULL) {
1484 
1485     SetObjectExtra (p, fpf, CleanupFieldsPage);
1486     fpf->dialog = (DialoG) p;
1487     fpf->todialog = GBQualPtrToFieldPage;
1488     fpf->fromdialog = FieldPageToGBQualPtr;
1489     fpf->testdialog = NULL;
1490 
1491     if (sfp != NULL && sfp->data.choice == SEQFEAT_IMP) {
1492       imp = (ImpFeatPtr) sfp->data.value.ptrvalue;
1493       if (imp != NULL && StringICmp (imp->key, "gap") == 0) {
1494         is_gap = TRUE;
1495       }
1496     }
1497 
1498     gbq = NULL;
1499     if (sfp != NULL) {
1500       gbq = sfp->qual;
1501     }
1502 
1503     j = 0;
1504     hasillegal = FALSE;
1505     for (i = 0; i < ParFlat_TOTAL_GBQUAL; i++) {
1506       seen [i] = 0;
1507     }
1508     num = 0;
1509 
1510     if (name != NULL) {
1511       index = GBFeatKeyNameValid (&name, FALSE);
1512       if (index >= 0) {
1513 
1514         sefp = &(ParFlat_GBFeat [index]);
1515 
1516         for (i = 0; i < sefp->mand_num; i++) {
1517           qual = sefp->mand_qual [i];
1518           if (qual > -1 && ShouldBeAGBQual (sfp == NULL ? FEATDEF_ANY : sfp->idx.subtype, qual, allowProductGBQual)) {
1519             seen [qual] = LEGAL_FEATURE;
1520           }
1521         }
1522         if (StringCmp (name, "repeat_region") == 0) {
1523           seen [GBQUAL_map] = TRUE;
1524         }
1525         if (StringCmp (name, "operon") == 0) {
1526           seen [GBQUAL_operon] = TRUE;
1527         }
1528         for (i = 0; i < sefp->opt_num; i++) {
1529           qual = sefp->opt_qual [i];
1530           if (qual > -1 && ShouldBeAGBQual (sfp == NULL ? FEATDEF_ANY : sfp->idx.subtype, qual, allowProductGBQual)) {
1531             seen [qual] = LEGAL_FEATURE;
1532           }
1533         }
1534       }
1535     } else if (sfp != NULL && sfp->data.choice == SEQFEAT_CDREGION) {
1536       /*
1537       seen [GBQUAL_exception] = LEGAL_FEATURE;
1538       seen [GBQUAL_pseudo] = LEGAL_FEATURE;
1539       */
1540     }
1541 
1542     while (gbq != NULL) {
1543       qual = GBQualNameValid (gbq->qual);
1544       if (qual > -1) {
1545         if (seen [qual] == 0 && qual != GBQUAL_experiment && qual != GBQUAL_inference) {
1546           seen [qual] = ILLEGAL_FEATURE;
1547           hasillegal = TRUE;
1548         }
1549       }
1550       gbq = gbq->next;
1551     }
1552 
1553     SelectFont (programFont);
1554     max = 0;
1555     for (i = 0; i < ParFlat_TOTAL_GBQUAL; i++) {
1556       if (seen [i] > 0) {
1557         num++;
1558         if (seen [i] == LEGAL_FEATURE) {
1559           StringNCpy_0 (str, ParFlat_GBQual_names [i].name, sizeof (str));
1560           wid = StringWidth (str) + 2;
1561         } else {
1562           str [0] = '\0';
1563           if (name != NULL) {
1564             StringCpy (str, "*");
1565           }
1566           StringNCat (str, ParFlat_GBQual_names [i].name, sizeof (str) - 2);
1567           wid = StringWidth (str) + 2;
1568         }
1569         if (wid > max) {
1570           max = wid;
1571         }
1572       }
1573     }
1574     SelectFont (systemFont);
1575 
1576     fpf->numfields = num;
1577     fpf->fields = MemNew (sizeof (CharPtr) * (num + 1));
1578     fpf->values = MemNew (sizeof (TexT) * (num + 1));
1579     fpf->boxes = MemNew (sizeof (ButtoN) * (num + 1));
1580 
1581     g = HiddenGroup (p, 2, 0, NULL);
1582     j = 0;
1583     for (i = 0; i < ParFlat_TOTAL_GBQUAL; i++) {
1584       if (seen [i] == LEGAL_FEATURE) {
1585         fpf->fields [j] = StringSave (ParFlat_GBQual_names [i].name);
1586         ppt = StaticPrompt (g, fpf->fields [j], max, dialogTextHeight, programFont, 'l');
1587         if (ParFlat_GBQual_names [i].gbclass != Class_none) {
1588           fpf->values [j] = DialogText (g, "", 20, NULL);
1589           /*
1590           if (i == GBQUAL_estimated_length && is_gap) {
1591             Disable (fpf->values [j]);
1592           }
1593           */
1594         } else {
1595           fpf->boxes [j] = CheckBox (g, "", NULL);
1596           AlignObjects (ALIGN_MIDDLE, (HANDLE) ppt, (HANDLE) fpf->boxes [j], NULL);
1597         }
1598         j++;
1599       }
1600     }
1601     if (hasillegal && name != NULL) {
1602       StaticPrompt (p, "Illegal Qualifiers", 0, 0, programFont, 'c');
1603     }
1604     g = HiddenGroup (p, 2, 0, NULL);
1605     for (i = 0; i < ParFlat_TOTAL_GBQUAL; i++) {
1606       if (seen [i] == ILLEGAL_FEATURE) {
1607         fpf->fields [j] = StringSave (ParFlat_GBQual_names [i].name);
1608         str [0] = '\0';
1609         if (name != NULL) {
1610           StringCpy (str, "*");
1611         }
1612         StringNCat (str, fpf->fields [j], sizeof (str) - 2);
1613         ppt = StaticPrompt (g, str, max, dialogTextHeight, programFont, 'l');
1614         if (ParFlat_GBQual_names [i].gbclass != Class_none) {
1615           fpf->values [j] = DialogText (g, "", 20, NULL);
1616         } else {
1617           fpf->boxes [j] = CheckBox (g, "", NULL);
1618           AlignObjects (ALIGN_MIDDLE, (HANDLE) ppt, (HANDLE) fpf->boxes [j], NULL);
1619         }
1620         j++;
1621       }
1622     }
1623 
1624     if (j == 0) {
1625       StaticPrompt (p, "See Attributes page to set legal qualifiers for this feature.",
1626                     0, 0, programFont, 'c');
1627     }
1628   }
1629   return (DialoG) p;
1630 }
1631 
1632 static void ChangeCannedMessage (PopuP p)
1633 
1634 {
1635   FeatureFormPtr  ffp;
1636   Int2            val;
1637 
1638   ffp = (FeatureFormPtr) GetObjectExtra (p);
1639   if (ffp == NULL) return;
1640   val = GetValue (p);
1641   switch (val) {
1642     case 1 :
1643       if (Message (MSG_YN, "Clear the explanation field?") == ANS_YES) {
1644         SetTitle (ffp->exceptText, "");
1645         if (Message (MSG_YN, "Clear the exception flag?") == ANS_YES) {
1646           SetStatus (ffp->exception, FALSE);
1647         }
1648       }
1649       break;
1650     case 2 :
1651       SetTitle (ffp->exceptText, "RNA editing");
1652       SetStatus (ffp->exception, TRUE);
1653       break;
1654     case 3 :
1655       SetTitle (ffp->exceptText, "reasons given in citation");
1656       SetStatus (ffp->exception, TRUE);
1657       break;
1658     case 4 :
1659       SetTitle (ffp->exceptText, "ribosomal slippage");
1660       SetStatus (ffp->exception, TRUE);
1661       break;
1662     case 5 :
1663       SetTitle (ffp->exceptText, "trans-splicing");
1664       SetStatus (ffp->exception, TRUE);
1665       break;
1666     case 6 :
1667       SetTitle (ffp->exceptText, "artificial frameshift");
1668       SetStatus (ffp->exception, TRUE);
1669       break;
1670     case 7 :
1671       SetTitle (ffp->exceptText, "nonconsensus splice site");
1672       SetStatus (ffp->exception, TRUE);
1673       break;
1674     case 8 :
1675       SetTitle (ffp->exceptText, "rearrangement required for product");
1676       SetStatus (ffp->exception, TRUE);
1677       break;
1678     case 9 :
1679       SetTitle (ffp->exceptText, "alternative start codon");
1680       SetStatus (ffp->exception, TRUE);
1681       break;
1682     case 10 :
1683       SetTitle (ffp->exceptText, "annotated by transcript or proteomic data");
1684       SetStatus (ffp->exception, TRUE);
1685       break;
1686     case 11 :
1687       SetTitle (ffp->exceptText, "heterogeneous population sequenced");
1688       SetStatus (ffp->exception, TRUE);
1689       break;
1690     case 12 :
1691       SetTitle (ffp->exceptText, "low-quality sequence region");
1692       SetStatus (ffp->exception, TRUE);
1693       break;
1694     case 13 :
1695       SetTitle (ffp->exceptText, "unextendable partial coding region");
1696       SetStatus (ffp->exception, TRUE);
1697       break;
1698     default :
1699       break;
1700   }
1701 }
1702 
1703 static CharPtr crossRefWarn =
1704 "A gene mapped by cross-reference does not extend the range\n\
1705 of the indicated gene feature.  Overlap is the usual case, and\n\
1706 it does extend the selected gene.";
1707 
1708 static CharPtr suppressWarn =
1709 "This will suppress display of a gene qualifier even though\n\
1710 there is a gene feature that overlaps this one.";
1711 
1712 static void GeneXrefWarn (GrouP g)
1713 
1714 {
1715   Int2  val;
1716   Boolean indexerVersion;
1717 
1718   indexerVersion = (Boolean) (GetAppProperty ("InternalNcbiSequin") != NULL);
1719   if (indexerVersion) return;
1720 
1721   val = GetValue (g);
1722   if (val == 2) {
1723     Message (MSG_OK, "%s", crossRefWarn);
1724   } else if (val == 3) {
1725     Message (MSG_OK, "%s", suppressWarn);
1726   }
1727 }
1728 
1729 static CharPtr  commonRadioFormTabs [] = {
1730   "General", "Comment", "Citations", "Cross-Refs", "Evidence", "Identifiers", NULL, NULL
1731 };
1732 
1733 static CharPtr  commonNoCitFormTabs [] = {
1734   "General", "Comment", "Cross-Refs", "Evidence", "Identifiers", NULL, NULL
1735 };
1736 
1737 static DialoG NewCreateInferenceDialog (GrouP prnt);
1738 extern void Nlm_LaunchGeneFeatEd (ButtoN b);
1739 
1740 
1741 static CharPtr GetNameForFeature (SeqFeatPtr sfp)
1742 {
1743   FeatDefPtr curr;
1744   Uint1      key;
1745   CharPtr    label = NULL;
1746   CharPtr    featname = NULL;
1747   CharPtr    ptr;
1748   Char       ch;
1749 
1750   if (sfp != NULL) {
1751     curr = FeatDefFindNext (NULL, &key, &label, sfp->idx.subtype, TRUE);
1752     if (curr != NULL) {
1753       featname = StringSave (label);
1754       ptr = featname;
1755       ch = *ptr;
1756       while (ch != '\0') {
1757         if (IS_UPPER (ch)) {
1758           *ptr = TO_LOWER (ch);
1759         }
1760         ptr++;
1761         ch = *ptr;
1762       }
1763     }
1764   }
1765   return featname;
1766 }
1767 
1768 
1769 extern GrouP CreateCommonFeatureGroupEx (GrouP h, FeatureFormPtr ffp,
1770                                          SeqFeatPtr sfp, Boolean hasGeneControl,
1771                                          Boolean hasCitationTab, Boolean hasGeneSuppress)
1772 
1773 {
1774   ButtoN     b;
1775   GrouP      c;
1776   PopuP      canned;
1777   Boolean    cdsQuals;
1778   GrouP      f;
1779   GrouP      g;
1780   GBQualPtr  gbq;
1781   Boolean    hasQuals;
1782   Boolean    indexerVersion;
1783   Char       just;
1784   GrouP      k;
1785   GrouP      m;
1786   GrouP      p;
1787   Int2       page;
1788   PrompT     ppt1, ppt2;
1789   ButtoN     pseudo = NULL;
1790   GrouP      q;
1791   GrouP      r;
1792   GrouP      t;
1793   GrouP      v;
1794   GrouP      x;
1795   GrouP      y;
1796   CharPtr    featname;
1797 
1798   c = NULL;
1799   if (ffp != NULL) {
1800     hasQuals = FALSE;
1801     cdsQuals = FALSE;
1802     if (ffp->gbquals == NULL && sfp != NULL && sfp->qual != NULL) {
1803       for (gbq = sfp->qual; gbq != NULL && !hasQuals; gbq = gbq->next) {
1804         if (!ShouldSuppressGBQual(sfp->idx.subtype, gbq->qual)) {
1805           hasQuals = TRUE;
1806         }
1807       }
1808       /*
1809       if (GetAppProperty ("InternalNcbiSequin") != NULL) {
1810         if (sfp->data.choice == SEQFEAT_CDREGION) {
1811           cdsQuals = TRUE;
1812         }
1813       }
1814       */
1815     }
1816     m = HiddenGroup (h, -1, 0, NULL);
1817     SetGroupSpacing (m, 10, 10);
1818     ffp->commonPage = 0;
1819     if (cdsQuals) {
1820     } else if (hasQuals) {
1821       commonRadioFormTabs [6] = "Qualifiers";
1822       commonNoCitFormTabs [5] = "Qualifiers";
1823     }
1824     if (hasCitationTab) {
1825       ffp->commonRadio = CreateFolderTabs (m, commonRadioFormTabs, ffp->commonPage,
1826                                            0, 0, PROGRAM_FOLDER_TAB,
1827                                            ChangeSubGroup, (Pointer) ffp);
1828     } else {
1829       ffp->commonRadio = CreateFolderTabs (m, commonNoCitFormTabs, ffp->commonPage,
1830                                            0, 0, PROGRAM_FOLDER_TAB,
1831                                            ChangeSubGroup, (Pointer) ffp);
1832     }
1833     commonRadioFormTabs [6] = NULL;
1834     commonNoCitFormTabs [5] = NULL;
1835 
1836     p = HiddenGroup (m, 0, 0, NULL);
1837 
1838     c = HiddenGroup (p, -1, 0, NULL);
1839     SetGroupSpacing (c, 10, 10);
1840     f = HiddenGroup (c, -1, 0, NULL);
1841     r = HiddenGroup (f, 7, 0, NULL);
1842     StaticPrompt (r, "Flags", 0, popupMenuHeight, programFont, 'l');
1843     ffp->partial = CheckBox (r, "Partial", NULL);
1844     indexerVersion = (Boolean) (GetAppProperty ("InternalNcbiSequin") != NULL);
1845     if (! indexerVersion) {
1846       Disable (ffp->partial);
1847     }
1848     if (ffp->pseudo == NULL) {
1849       ffp->pseudo = CheckBox (r, "Pseudo", NULL);
1850       pseudo = ffp->pseudo; /* allows pseudo control on earlier feature-specific page */
1851     }
1852     if (indexerVersion) {
1853       StaticPrompt (r, "Evidence", 0, popupMenuHeight, programFont, 'l');
1854       ffp->evidence = PopupList (r, TRUE, NULL);
1855       PopupItem (ffp->evidence, " ");
1856       PopupItem (ffp->evidence, "Experimental");
1857       PopupItem (ffp->evidence, "Non-Experimental");
1858     }
1859     AlignObjects (ALIGN_MIDDLE, (HANDLE) ffp->partial,
1860                   (HANDLE) pseudo, (HANDLE) ffp->evidence, NULL);
1861     r = HiddenGroup (f, -3, 0, NULL);
1862     ffp->exception = CheckBox (r, "Exception", NULL);
1863     StaticPrompt (r, "Explanation", 0, dialogTextHeight, programFont, 'l');
1864     ffp->exceptText = DialogText (r, "", 12, NULL);
1865     AlignObjects (ALIGN_MIDDLE, (HANDLE) ffp->exception,
1866                  (HANDLE) ffp->exceptText, NULL);
1867     if (ffp->this_subtype == FEATDEF_CDS) {
1868       StaticPrompt (r, "Standard explanation", 0, popupMenuHeight, programFont, 'l');
1869       canned = PopupList (r, TRUE, ChangeCannedMessage);
1870       SetObjectExtra (canned, (Pointer) ffp, NULL);
1871       PopupItem (canned, " ");
1872       PopupItem (canned, "RNA editing");
1873       PopupItem (canned, "reasons given in citation");
1874       PopupItem (canned, "ribosomal slippage");
1875       PopupItem (canned, "trans-splicing");
1876       PopupItem (canned, "artificial frameshift");
1877       PopupItem (canned, "nonconsensus splice site");
1878       PopupItem (canned, "rearrangement required");
1879       PopupItem (canned, "alternative start codon");
1880       PopupItem (canned, "transcript or proteome data");
1881       PopupItem (canned, "heterogeneous population");
1882       PopupItem (canned, "low-quality sequence region");
1883       PopupItem (canned, "unextendable partial CDS");
1884       if (sfp != NULL && sfp->excpt) {
1885         if (StringICmp (sfp->except_text, "RNA editing") == 0) {
1886           SetValue (canned, 2);
1887         } else if (StringICmp (sfp->except_text, "reasons given in citation") == 0 ||
1888                    StringICmp (sfp->except_text, "reasons cited in publication") == 0) {
1889           SetValue (canned, 3);
1890         } else if (StringICmp (sfp->except_text, "ribosomal slippage") == 0 ||
1891                    StringICmp (sfp->except_text, "ribosome slippage") == 0) {
1892           SetValue (canned, 4);
1893         } else if (StringICmp (sfp->except_text, "trans-splicing") == 0 ||
1894                    StringICmp (sfp->except_text, "trans splicing") == 0) {
1895           SetValue (canned, 5);
1896         } else if (StringICmp (sfp->except_text, "artificial frameshift") == 0) {
1897           SetValue (canned, 6);
1898         } else if (StringICmp (sfp->except_text, "non-consensus splice site") == 0 ||
1899                    StringICmp (sfp->except_text, "nonconsensus splice site") == 0) {
1900           SetValue (canned, 7);
1901         } else if (StringICmp (sfp->except_text, "rearrangement required for product") == 0) {
1902           SetValue (canned, 8);
1903         } else if (StringICmp (sfp->except_text, "alternative start codon") == 0) {
1904           SetValue (canned, 9);
1905         } else if (StringICmp (sfp->except_text, "annotated by transcript or proteomic data") == 0) {
1906           SetValue (canned, 10);
1907         } else if (StringICmp (sfp->except_text, "heterogeneous population sequenced") == 0) {
1908           SetValue (canned, 11);
1909         } else if (StringICmp (sfp->except_text, "low-quality sequence region") == 0) {
1910           SetValue (canned, 12);
1911         } else if (StringICmp (sfp->except_text, "unextendable partial coding region") == 0) {
1912           SetValue (canned, 13);
1913         }
1914       } else {
1915         SetValue (canned, 1);
1916       }
1917     }
1918 
1919     if (cdsQuals) {
1920       /*
1921       ffp->gbquals = CreateImportFields (c, NULL, sfp, FALSE);
1922       */
1923     }
1924 
1925     g = NULL;
1926     k = NULL;
1927     ffp->gene = NULL;
1928     ffp->genePopup = NULL;
1929     ffp->geneList = NULL;
1930     ffp->geneNames = NULL;
1931     ffp->useGeneXref = NULL;
1932     ffp->newGeneGrp = NULL;
1933     ffp->geneSymbol = NULL;
1934     ffp->geneAllele = NULL;
1935     ffp->geneDesc = NULL;
1936     ffp->locusTag = NULL;
1937     ffp->geneSynonym = NULL;
1938     for (page = 0; page < 8; page++) {
1939       ffp->commonSubGrp [page] = NULL;
1940     }
1941     page = 0;
1942 
1943     if (hasGeneControl) {
1944       g = HiddenGroup (c, -2, 0, NULL);
1945       StaticPrompt (g, "Gene", 0, popupMenuHeight, programFont, 'l');
1946       v = HiddenGroup (g, 0, 0, NULL);
1947       ffp->genePopup = PopupList (v, TRUE, (PupActnProc) ChangeGenePopupOrList);
1948       SetObjectExtra (ffp->genePopup, (Pointer) ffp, NULL);
1949       PopupItem (ffp->genePopup, " ");
1950       PopupItem (ffp->genePopup, "New:");
1951       SetValue (ffp->genePopup, 1);
1952       Hide (ffp->genePopup);
1953       ffp->geneList = SingleList (v, 6, 3, (LstActnProc) ChangeGenePopupOrList);
1954       SetObjectExtra (ffp->geneList, (Pointer) ffp, NULL);
1955       ListItem (ffp->geneList, " ");
1956       ListItem (ffp->geneList, "New:");
1957       SetValue (ffp->geneList, 1);
1958       Hide (ffp->geneList);
1959       k = HiddenGroup (c, 3, 0, NULL);
1960       StaticPrompt (k, "Map by", 0, stdLineHeight, programFont, 'l');
1961       ffp->useGeneXref = HiddenGroup (k, 3, 0, GeneXrefWarn);
1962       SetObjectExtra (ffp->useGeneXref, ffp, NULL);
1963       RadioButton (ffp->useGeneXref, "Overlap");
1964       RadioButton (ffp->useGeneXref, "Cross-reference");
1965       RadioButton (ffp->useGeneXref, "Suppress");
1966       SetValue (ffp->useGeneXref, 1);
1967       y = HiddenGroup (c, 0, 0, NULL);
1968       ffp->newGeneGrp = HiddenGroup (y, 2, 0, NULL);
1969       StaticPrompt (ffp->newGeneGrp, "Gene Symbol", 0, dialogTextHeight, programFont, 'l');
1970       ffp->geneSymbol = DialogText (ffp->newGeneGrp, "", 20, NULL);
1971       StaticPrompt (ffp->newGeneGrp, "Allele", 0, dialogTextHeight, programFont, 'l');
1972       ffp->geneAllele = DialogText (ffp->newGeneGrp, "", 20, NULL);
1973       StaticPrompt (ffp->newGeneGrp, "Description", 0, dialogTextHeight, programFont, 'l');
1974       ffp->geneDesc = DialogText (ffp->newGeneGrp, "", 20, NULL);
1975       StaticPrompt (ffp->newGeneGrp, "Locus Tag", 0, dialogTextHeight, programFont, 'l');
1976       ffp->locusTag = DialogText (ffp->newGeneGrp, "", 20, NULL);
1977       StaticPrompt (ffp->newGeneGrp, "Synonym", 0, dialogTextHeight, programFont, 'l');
1978       ffp->geneSynonym = DialogText (ffp->newGeneGrp, "", 20, NULL);
1979       Hide (ffp->newGeneGrp);
1980       ffp->editGeneBtn = PushButton (y, "Edit Gene Feature", Nlm_LaunchGeneFeatEd);
1981       SetObjectExtra (ffp->editGeneBtn, ffp, NULL);
1982       Hide (ffp->editGeneBtn);
1983     } else if (hasGeneSuppress) {
1984       k = HiddenGroup (c, 3, 0, NULL);
1985       StaticPrompt (k, "Map by", 0, stdLineHeight, programFont, 'l');
1986       ffp->useGeneXref = HiddenGroup (k, 3, 0, GeneXrefWarn);
1987       SetObjectExtra (ffp->useGeneXref, ffp, NULL);
1988       RadioButton (ffp->useGeneXref, "Overlap");
1989       b = RadioButton (ffp->useGeneXref, "Cross-reference");
1990       Disable (b);
1991       RadioButton (ffp->useGeneXref, "Suppress");
1992       SetValue (ffp->useGeneXref, 1);
1993       y = HiddenGroup (c, 0, 0, NULL);
1994     }
1995     ffp->commonSubGrp [page] = c;
1996     page++;
1997     AlignObjects (ALIGN_CENTER, (HANDLE) f, (HANDLE) g,
1998                   (HANDLE) k, (HANDLE) ffp->newGeneGrp,
1999                   (HANDLE) ffp->editGeneBtn, NULL);
2000 
2001     c = HiddenGroup (p, -1, 0, NULL);
2002     SetGroupSpacing (c, 10, 10);
2003     q = HiddenGroup (c, 0, 2, NULL);
2004     StaticPrompt (q, "Comment", 25 * stdCharWidth, 0, programFont, 'c');
2005     if (GetAppProperty ("InternalNcbiSequin") != NULL) {
2006       ffp->comment = ScrollText (q, 25, 10, programFont, TRUE, NULL);
2007     } else {
2008       ffp->comment = ScrollText (q, 25, 5, programFont, TRUE, NULL);
2009     }
2010     ffp->commonSubGrp [page] = c;
2011     Hide (ffp->commonSubGrp [page]);
2012     page++;
2013 
2014     if (hasCitationTab) {
2015       c = HiddenGroup (p, -1, 0, NULL);
2016       SetGroupSpacing (c, 10, 10);
2017       ffp->featcits = CreateCitOnFeatDialog (c, NULL);
2018       b = PushButton (c, "Edit Citations", EditFeatCitsProc);
2019       SetObjectExtra (b, ffp, NULL);
2020       ffp->commonSubGrp [page] = c;
2021       AlignObjects (ALIGN_CENTER, (HANDLE) ffp->featcits, (HANDLE) b, NULL);
2022       Hide (ffp->commonSubGrp [page]);
2023       page++;
2024     }
2025 
2026     c = HiddenGroup (p, -1, 0, NULL);
2027     SetGroupSpacing (c, 10, 10);
2028     if (GetAppProperty ("ReadOnlyDbTags") == NULL) {
2029       just = 'c';
2030     } else {
2031       just = 'l';
2032       StaticPrompt (c, "This page is read-only", 15 * stdCharWidth, 0, programFont, 'c');
2033     }
2034     t = HiddenGroup (c, 2, 0, NULL);
2035     StaticPrompt (t, "Database", 7 * stdCharWidth, 0, programFont, just);
2036     StaticPrompt (t, "Object ID", 8 * stdCharWidth, 0, programFont, just);
2037     ffp->dbxrefs = CreateDbtagDialog (c, 3, -1, 7, 8);
2038     ffp->commonSubGrp [page] = c;
2039     Hide (ffp->commonSubGrp [page]);
2040     page++;
2041 
2042     c = HiddenGroup (p, -1, 0, NULL);
2043     SetGroupSpacing (c, 10, 10);
2044     q = HiddenGroup (c, 0, -6, NULL);
2045     ppt1 = StaticPrompt (q, "Experiment", 0, 0, programFont, 'c');
2046     ffp->experiment = CreateVisibleStringDialog (q, 3, -1, 15);
2047     ppt2 = StaticPrompt (q, "Inference", 0, 0, programFont, 'c');
2048     /*
2049     ffp->inference = CreateInferenceDialog (q, 3, 2, 15);
2050     */
2051     ffp->inference = NewCreateInferenceDialog (q);
2052     AlignObjects (ALIGN_CENTER, (HANDLE) ppt1, (HANDLE) ffp->experiment,
2053                   (HANDLE) ppt2, (HANDLE) ffp->inference, NULL);
2054     ffp->commonSubGrp [page] = c;
2055     Hide (ffp->commonSubGrp [page]);
2056     page++;
2057 
2058     c = HiddenGroup (p, -1, 0, NULL);
2059     SetGroupSpacing (c, 10, 10);
2060     t = HiddenGroup (c, 2, 0, NULL);
2061     SetGroupSpacing (t, 10, 30);
2062     StaticPrompt (t, "Feature ID for this feature", 0, dialogTextHeight, programFont, 'l');
2063     ffp->featid = DialogText (t, "", 8, NULL);
2064     StaticPrompt (t, "ID Xref to associated feature", 0, dialogTextHeight, programFont, 'l');
2065     ffp->fidxref = DialogText (t, "", 8, NULL);
2066     if (! indexerVersion) {
2067       Disable (ffp->featid);
2068       Disable (ffp->fidxref);
2069     }
2070     ffp->commonSubGrp [page] = c;
2071     Hide (ffp->commonSubGrp [page]);
2072     page++;
2073 
2074 
2075     c = HiddenGroup (p, -1, 0, NULL);
2076     SetGroupSpacing (c, 10, 10);
2077     x = NULL;
2078     if (hasQuals && ffp->gbquals == NULL) {
2079       x = HiddenGroup (c, -1, 0, NULL);
2080       featname = GetNameForFeature (sfp);
2081       ffp->gbquals = NewCreateImportFields (x, featname, sfp, FALSE);
2082       featname = MemFree (featname);
2083     }
2084     ffp->commonSubGrp [page] = c;
2085     Hide (ffp->commonSubGrp [page]);
2086     page++;
2087 
2088 
2089     AlignObjects (ALIGN_CENTER, (HANDLE) ffp->commonRadio, (HANDLE) ffp->commonSubGrp [0],
2090                   (HANDLE) ffp->commonSubGrp [1], (HANDLE) ffp->commonSubGrp [2],
2091                   (HANDLE) ffp->commonSubGrp [3], (HANDLE) ffp->commonSubGrp [4],
2092                   (HANDLE) ffp->commonSubGrp [5], (HANDLE) ffp->commonSubGrp [6],
2093                   (HANDLE) ffp->commonSubGrp [7], NULL);
2094   }
2095   return c;
2096 }
2097 
2098 extern GrouP CreateCommonFeatureGroup (GrouP h, FeatureFormPtr ffp,
2099                                        SeqFeatPtr sfp, Boolean hasGeneControl,
2100                                        Boolean hasCitationTab)
2101 
2102 {
2103   return CreateCommonFeatureGroupEx (h, ffp, sfp, hasGeneControl, hasCitationTab, FALSE);
2104 }
2105 
2106 static Boolean DlgutilFindBspItem (GatherContextPtr gcp)
2107 
2108 {
2109   BioseqPtr  PNTR bspp;
2110 
2111   bspp = (BioseqPtr PNTR) gcp->userdata;
2112   if (bspp != NULL && gcp->thistype == OBJ_BIOSEQ) {
2113     *bspp = (BioseqPtr) gcp->thisitem;
2114   }
2115   return TRUE;
2116 }
2117 
2118 extern void SetNewFeatureDefaultInterval (FeatureFormPtr ffp)
2119 
2120 {
2121   BioseqPtr     bsp;
2122   SelStructPtr  sel;
2123   SeqIntPtr     sip;
2124   SeqLocPtr     slp;
2125 
2126   if (ffp == NULL) return;
2127   bsp = NULL;
2128   GatherItem (ffp->input_entityID, ffp->input_itemID, ffp->input_itemtype,
2129               (Pointer) (&bsp), DlgutilFindBspItem);
2130   if (bsp == NULL) return;
2131   slp = NULL;
2132   sel = ObjMgrGetSelected ();
2133   if (sel != NULL && sel->next == NULL && sel->entityID == ffp->input_entityID &&
2134       sel->itemID == ffp->input_itemID && sel->itemtype == ffp->input_itemtype) {
2135     if (sel->regiontype == 1 && sel->region != NULL) {
2136       if (GetBioseqGivenSeqLoc ((SeqLocPtr) sel->region, ffp->input_entityID) == bsp) {
2137         slp = AsnIoMemCopy (sel->region,
2138                             (AsnReadFunc) SeqLocAsnRead,
2139                             (AsnWriteFunc) SeqLocAsnWrite);
2140       }
2141     }
2142   }
2143   if (slp == NULL) {
2144     slp = ValNodeNew (NULL);
2145     if (slp == NULL) return;
2146     sip = SeqIntNew ();
2147     if (sip == NULL) {
2148       slp = SeqLocFree (slp);
2149       return;
2150     }
2151     slp->choice = SEQLOC_INT;
2152     slp->data.ptrvalue = (Pointer) sip;
2153     sip->from = 0;
2154     sip->to = bsp->length - 1;
2155     sip->strand = Seq_strand_plus;
2156     sip->id = SeqIdStripLocus (SeqIdDup (SeqIdFindBest (bsp->id, 0)));
2157   }
2158   if (slp != NULL) {
2159     PointerToDialog (ffp->location, (Pointer) slp);
2160     SeqLocFree (slp);
2161   }
2162 }
2163 
2164 extern Boolean FileToScrollText (TexT t, CharPtr path)
2165 
2166 {
2167   FILE     *fp;
2168   Int8     len;
2169   Int4     read_len;
2170   Int4     max;
2171   CharPtr  str;
2172 #ifdef WIN_MAC
2173   CharPtr  p;
2174 #endif
2175 #if (defined(OS_DOS) || defined (OS_NT))
2176   CharPtr  p;
2177   CharPtr  q;
2178 #endif
2179 
2180   if (t != NULL && path != NULL && *path != '\0') {
2181     len = FileLength (path);
2182     max = (Int4) INT2_MAX;
2183 #ifdef WIN_MOTIF
2184     max = INT4_MAX;
2185 #endif
2186 #ifdef WIN_MSWIN
2187     max = INT4_MAX;
2188 #endif
2189 #ifdef WIN_MAC
2190 #ifdef OS_UNIX_DARWIN
2191     max = INT4_MAX;
2192 #endif
2193 #endif
2194     if (len > 0 && len < max - 4) {
2195       str = MemNew (sizeof (char) * ((size_t)len + 3));
2196       if (str != NULL) {
2197         fp = FileOpen (path, "r");
2198         if (fp != NULL) {
2199           read_len = FileRead (str, sizeof (char), (size_t) len, fp);
2200           str [ read_len ] = 0;
2201 #if (defined(OS_DOS) || defined (OS_NT))
2202           p = str;
2203           q = str;
2204           while (*p) {
2205             if (*p == '\r') {
2206               p++;
2207             } else {
2208               *q = *p;
2209               p++;
2210               q++;
2211             }
2212           }
2213           *q = '\0';
2214 #endif
2215 #ifdef WIN_MAC
2216           p = str;
2217           while (*p) {
2218             if (*p == '\r' || *p == '\n') {
2219               *p = '\015';
2220             }
2221             p++;
2222           }
2223 #endif
2224           FileClose (fp);
2225           SetTitle (t, str);
2226         }
2227         MemFree (str);
2228         return TRUE;
2229       }
2230     }
2231   }
2232   return FALSE;
2233 }
2234 
2235 extern void ScrollTextToFile (TexT t, CharPtr path)
2236 
2237 {
2238   FILE     *fp;
2239   size_t   len;
2240   CharPtr  str;
2241 #ifdef WIN_MAC
2242   CharPtr  p;
2243 #endif
2244 
2245   if (t != NULL && path != NULL && *path != '\0') {
2246     len = TextLength (t);
2247     if (len > 0) {
2248 #ifdef WIN_MAC
2249       fp = FileOpen (path, "r");
2250       if (fp != NULL) {
2251         FileClose (fp);
2252       } else {
2253         FileCreate (path, "TEXT", "ttxt");
2254       }
2255 #endif
2256       fp = FileOpen (path, "w");
2257       if (fp != NULL) {
2258         str = MemNew (sizeof (char) * (len + 3));
2259         if (str != NULL) {
2260           GetTitle (t, str, len + 1);
2261 #ifdef WIN_MAC
2262           p = str;
2263           while (*p) {
2264             if (*p == '\r' || *p == '\n') {
2265               *p = '\n';
2266             }
2267             p++;
2268           }
2269 #endif
2270           FileWrite (str, sizeof (char), len, fp);
2271           MemFree (str);
2272         }
2273         FileClose (fp);
2274       }
2275     }
2276   }
2277 }
2278 
2279 extern void FileToClipboard (CharPtr path)
2280 
2281 {
2282   FILE     *fp;
2283   Int8     len;
2284   Int4     max;
2285   CharPtr  str;
2286 #ifdef WIN_MAC
2287   CharPtr  p;
2288 #endif
2289 #if (defined(OS_DOS) || defined (OS_NT))
2290   CharPtr  p;
2291   CharPtr  q;
2292 #endif
2293 
2294   if (path != NULL && *path != '\0') {
2295     len = FileLength (path);
2296 #ifdef WIN_MOTIF
2297     max = INT4_MAX;
2298 #else
2299     max = (Int4) INT2_MAX;
2300 #endif
2301     if (len > 0 && len < max - 4) {
2302       str = MemNew (sizeof (char) * ((size_t)len + 3));
2303       if (str != NULL) {
2304         fp = FileOpen (path, "r");
2305         if (fp != NULL) {
2306           FileRead (str, sizeof (char), (size_t) len, fp);
2307 #if (defined(OS_DOS) || defined (OS_NT))
2308           p = str;
2309           q = str;
2310           while (*p) {
2311             if (*p == '\r') {
2312               p++;
2313             } else {
2314               *q = *p;
2315               p++;
2316               q++;
2317             }
2318           }
2319           *q = '\0';
2320 #endif
2321 #ifdef WIN_MAC
2322           p = str;
2323           while (*p) {
2324             if (*p == '\r' || *p == '\n') {
2325               *p = '\015';
2326             }
2327             p++;
2328           }
2329 #endif
2330           FileClose (fp);
2331           Nlm_StringToClipboard (str);
2332         }
2333         MemFree (str);
2334       }
2335     }
2336   }
2337 }
2338 
2339 typedef struct textviewform {
2340   FORM_MESSAGE_BLOCK
2341 
2342   DoC              doc;
2343   TexT             text;
2344 
2345   TexT             find;
2346 } TextViewForm, PNTR TextViewFormPtr;
2347 
2348 static ParData txtParFmt = {FALSE, FALSE, FALSE, FALSE, TRUE, 0, 0};
2349 static ColData txtColFmt = {0, 0, 80, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, TRUE};
2350 
2351 static void ResizeTextViewer (WindoW w)
2352 
2353 {
2354   Int2             height;
2355   RecT             r;
2356   RecT             s;
2357   TextViewFormPtr  tfp;
2358   Int2             width;
2359 
2360   tfp = (TextViewFormPtr) GetObjectExtra (w);
2361   if (tfp != NULL) {
2362     WatchCursor ();
2363     ObjectRect (w, &r);
2364     width = r.right - r.left;
2365     height = r.bottom - r.top;
2366     if (tfp->doc != NULL) {
2367       GetPosition (tfp->doc, &s);
2368       s.right = width - s.left;
2369       s.bottom = height - s.left;
2370       SetPosition (tfp->doc, &s);
2371       AdjustPrnt (tfp->doc, &s, FALSE);
2372       txtColFmt.pixWidth = screenRect.right - screenRect.left;
2373       txtColFmt.pixInset = 8;
2374       if (Visible (tfp->doc) && AllParentsVisible (tfp->doc)) {
2375         UpdateDocument (tfp->doc, 0, 0);
2376       }
2377     }
2378     if (tfp->text != NULL) {
2379       GetPosition (tfp->text, &s);
2380       s.right = width - s.left;
2381       s.bottom = height - s.left;
2382       SetPosition (tfp->text, &s);
2383       AdjustPrnt (tfp->text, &s, FALSE);
2384     }
2385     ArrowCursor ();
2386     Update ();
2387   }
2388 }
2389 
2390 static Boolean ExportTextViewForm (ForM f, CharPtr filename)
2391 
2392 {
2393   FILE             *fp;
2394   Char             path [PATH_MAX];
2395   TextViewFormPtr  tfp;
2396 
2397   tfp = (TextViewFormPtr) GetObjectExtra (f);
2398   if (tfp != NULL && (tfp->doc != NULL || tfp->text != NULL)) {
2399     path [0] = '\0';
2400     StringNCpy_0 (path, filename, sizeof (path));
2401     if (path [0] != '\0' || GetOutputFileName (path, sizeof (path), NULL)) {
2402 #ifdef WIN_MAC
2403       fp = FileOpen (path, "r");
2404       if (fp != NULL) {
2405         FileClose (fp);
2406       } else {
2407         FileCreate (path, "TEXT", "ttxt");
2408       }
2409 #endif
2410       if (tfp->doc != NULL) {
2411         fp = FileOpen (path, "w");
2412         if (fp != NULL) {
2413           SaveDocument (tfp->doc, fp);
2414           FileClose (fp);
2415           return TRUE;
2416         }
2417       } else if (tfp->text != NULL) {
2418         ScrollTextToFile (tfp->text, path);
2419         return TRUE;
2420       }
2421     }
2422   }
2423   return FALSE;
2424 }
2425 
2426 static void LIBCALL PrintTextViewForm (Pointer formDataPtr)
2427 
2428 {
2429   TextViewFormPtr  tfp;
2430 
2431   tfp = (TextViewFormPtr) formDataPtr;
2432   if (tfp != NULL && tfp->doc != NULL) {
2433     PrintDocument (tfp->doc);
2434   }
2435 }
2436 
2437 static void TextViewFormMessage (ForM f, Int2 mssg)
2438 
2439 {
2440   TextViewFormPtr  tfp;
2441 
2442   tfp = (TextViewFormPtr) GetObjectExtra (f);
2443   if (tfp != NULL) {
2444     switch (mssg) {
2445       case VIB_MSG_EXPORT :
2446         ExportTextViewForm (f, NULL);
2447         break;
2448       case VIB_MSG_CLOSE :
2449         Remove (f);
2450         break;
2451       case VIB_MSG_PRINT :
2452         PrintTextViewForm (tfp);
2453         break;
2454       case VIB_MSG_CUT :
2455         StdCutTextProc (NULL);
2456         break;
2457       case VIB_MSG_COPY :
2458         StdCopyTextProc (NULL);
2459         break;
2460       case VIB_MSG_PASTE :
2461         StdPasteTextProc (NULL);
2462         break;
2463       case VIB_MSG_DELETE :
2464         StdDeleteTextProc (NULL);
2465         break;
2466       default :
2467         if (tfp->appmessage != NULL) {
2468           tfp->appmessage (f, mssg);
2469         }
2470         break;
2471     }
2472   }
2473 }
2474 
2475 
2476 static void FindInGeneralText (ButtoN b)
2477 
2478 {
2479   Int2             actual;
2480   Char             buf [1030];
2481   Char             ch;
2482   Int2             cnt;
2483   Int8             cntr;
2484   Int2             first;
2485   FILE             *fp;
2486   Char             lastch;
2487   Int4             line = 0;
2488   ValNodePtr       matches;
2489   Int2             next;
2490   Int2             offset = 0;
2491   Char             path [PATH_MAX];
2492   CharPtr          ptr;
2493   Int4             state;
2494   CharPtr          str;
2495   TextFsaPtr       tbl;
2496   TextViewFormPtr  tfp;
2497   Int4             max;
2498 
2499   tfp = (TextViewFormPtr) GetObjectExtra (b);
2500   if (tfp == NULL) return;
2501   if (tfp->doc != NULL) {
2502     GetOffset (tfp->doc, NULL, &offset);
2503   } else if (tfp->text != NULL) {
2504     GetOffset (tfp->text, NULL, &offset);
2505   }
2506   first = -1;
2507   next = -1;
2508   max = INT2_MAX;
2509 
2510   str = SaveStringFromText (tfp->find);
2511 
2512   if (StringDoesHaveText (str)) {
2513     TmpNam (path);
2514     if (ExportForm (tfp->form, path)) {
2515       tbl = TextFsaNew ();
2516       if (tbl != NULL) {
2517         TextFsaAdd (tbl, str);
2518         fp = FileOpen (path, "r");
2519         if (fp != NULL) {
2520           line = 0;
2521           state = 0;
2522           cntr = FileLength (path);
2523           cnt = (Int2) MIN (cntr, 1024L);
2524           lastch = '\0';
2525           while (cnt > 0 && cntr > 0 && line <= max && 
2526                  ((next == -1 && offset > first) || first == -1)) {
2527             actual = (Int2) FileRead (buf, 1, cnt, fp);
2528             if (actual > 0) {
2529               cnt = actual;
2530               buf [cnt] = '\0';
2531               ptr = buf;
2532               ch = *ptr;
2533               while (ch != '\0') {
2534                 if (ch == '\n' || ch == '\r') {
2535                   if (ch == '\n' && lastch == '\r') {
2536                     /* do not increment line */
2537                   } else if (ch == '\r' && lastch == '\n') {
2538                     /* do not increment line */
2539                   } else {
2540                     line++;
2541                   }
2542                 }
2543                 state = TextFsaNext (tbl, state, ch, &matches);
2544                 if (matches != NULL) {
2545                   if (first == -1) {
2546                     first = line;
2547                   }
2548                   if (next == -1 && line > offset) {
2549                     next = line;
2550                   }
2551                 }
2552                 lastch = ch;
2553                 ptr++;
2554                 ch = *ptr;
2555               }
2556               cntr -= cnt;
2557               cnt = (Int2) MIN (cntr, 1024L);
2558             } else {
2559               cnt = 0;
2560               cntr = 0;
2561             }
2562           }
2563         }
2564         FileClose (fp);
2565       }
2566       TextFsaFree (tbl);
2567     }
2568     FileRemove (path);
2569   }
2570   MemFree (str);
2571   if (line > max) {
2572     Message (MSG_ERROR, "Too many lines for search");
2573   }
2574 
2575   if (next >= 0) {
2576     offset = next;
2577   } else if (first >= 0) {
2578     offset = first;
2579   } else return;
2580   if (tfp->doc != NULL) {
2581     SetOffset (tfp->doc, 0, offset);
2582     Update ();
2583   } else if (tfp->text != NULL) {
2584     SetOffset (tfp->text, 0, offset);
2585     Update ();
2586   }
2587 }
2588 
2589 typedef struct repopulateviewer
2590 {
2591   Nlm_RepopulateViewer   repopulate_func; 
2592   Pointer                repopulate_data;
2593   Nlm_RepopulateDataFree free_data_func;
2594   TextViewFormPtr        tfp;
2595   FonT                   fnt;
2596 } RepopulateViewerData, PNTR RepopulateViewerPtr;
2597 
2598 static void CleanupRepopulateViewer (Nlm_GraphiC g, Nlm_VoidPtr data)
2599 {
2600   RepopulateViewerPtr rp;
2601   
2602   rp = (RepopulateViewerPtr) data;
2603   if (rp != NULL && rp->free_data_func != NULL)
2604   {
2605     (rp->free_data_func)(rp->repopulate_data);
2606   }
2607   
2608   StdCleanupExtraProc (g, data);
2609 }
2610 
2611 static void RepopulateViewer (ButtoN b)
2612 {
2613   RepopulateViewerPtr rp;
2614   CharPtr             new_path;
2615   
2616   rp = (RepopulateViewerPtr) GetObjectExtra (b);
2617   
2618   if (rp == NULL || rp->repopulate_func == NULL)
2619   {
2620     return;
2621   }
2622   
2623   new_path = (rp->repopulate_func) (rp->repopulate_data);
2624   if (new_path == NULL)
2625   {
2626     return;
2627   }
2628   
2629   if (rp->tfp->text != NULL)
2630   {
2631     FileToScrollText (rp->tfp->text, new_path);
2632   }
2633   else if (rp->tfp->doc != NULL)
2634   {
2635     txtColFmt.pixWidth = screenRect.right - screenRect.left;
2636     txtColFmt.pixInset = 8;
2637     DisplayFancy (rp->tfp->doc, new_path, &txtParFmt, &txtColFmt, rp->fnt, 0);
2638   }
2639   FileRemove (new_path);
2640   new_path = MemFree (new_path);
2641 }
2642 
2643 static void 
2644 LaunchGeneralTextViewerEx 
2645 (CharPtr path,
2646  CharPtr title, 
2647  Boolean useScrollText,
2648  Nlm_RepopulateViewer   repopulate_func, 
2649  Pointer                repopulate_data,
2650  Nlm_RepopulateDataFree free_data_func)
2651 
2652 {
2653   ButtoN              b;
2654   FonT                fnt;
2655   GrouP               g;
2656   Int2                pixheight;
2657   Int2                pixwidth;
2658   StdEditorProcsPtr   sepp;
2659   TextViewFormPtr     tfp;
2660   TextViewProcsPtr    tvpp;
2661   RepopulateViewerPtr rp;
2662   WindoW              w;
2663 #ifndef WIN_MAC
2664   MenU                m;
2665 #endif
2666 
2667   tfp = (TextViewFormPtr) MemNew (sizeof (TextViewForm));
2668   if (tfp == NULL) return;
2669 
2670   w = DocumentWindow (-50, -33, -10, -10, title, StdCloseWindowProc, ResizeTextViewer);
2671   SetObjectExtra (w, tfp, StdCleanupFormProc);
2672   tfp->form = (ForM) w;
2673   tfp->exportform = ExportTextViewForm;
2674   tfp->formmessage = TextViewFormMessage;
2675 
2676   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
2677   if (sepp != NULL) {
2678     SetActivate (w, sepp->activateForm);
2679     tfp->appmessage = sepp->handleMessages;
2680   }
2681 
2682   fnt = programFont;
2683   pixwidth = 35 * stdCharWidth + 17;
2684   pixheight = 20 * stdLineHeight;
2685 
2686   tvpp = (TextViewProcsPtr) GetAppProperty ("TextDisplayForm");
2687   if (tvpp != NULL) {
2688     pixwidth = MAX (pixwidth, tvpp->minPixelWidth);
2689     pixheight = MAX (pixheight, tvpp->minPixelHeight);
2690     if (tvpp->displayFont != NULL) {
2691       fnt = tvpp->displayFont;
2692     }
2693     if (tvpp->activateForm != NULL) {
2694       SetActivate (w, tvpp->activateForm);
2695     }
2696   }
2697 
2698 #ifndef WIN_MAC
2699   m = PulldownMenu (w, "File");
2700   FormCommandItem (m, "Export...", (BaseFormPtr) tfp, VIB_MSG_EXPORT);
2701   SeparatorItem (m);
2702   FormCommandItem (m, "Close", (BaseFormPtr) tfp, VIB_MSG_CLOSE);
2703   if (tvpp != NULL && tvpp->useScrollText) {
2704     m = PulldownMenu (w, "Edit");
2705     FormCommandItem (m, CUT_MENU_ITEM, (BaseFormPtr) tfp, VIB_MSG_CUT);
2706     FormCommandItem (m, COPY_MENU_ITEM, (BaseFormPtr) tfp, VIB_MSG_COPY);
2707     FormCommandItem (m, PASTE_MENU_ITEM, (BaseFormPtr) tfp, VIB_MSG_PASTE);
2708     FormCommandItem (m, CLEAR_MENU_ITEM, (BaseFormPtr) tfp, VIB_MSG_DELETE);
2709   }
2710 #endif
2711 
2712 #ifdef WIN_MAC
2713   if (useScrollText) {
2714     if (FileLength (path) > 32767) {
2715       /* text edit window has maximum length on Mac */
2716       useScrollText = FALSE;
2717     }
2718   }
2719 #endif
2720 
2721   /* right now Find button is only in indexer Sequin */
2722   if (useScrollText) {
2723     g = HiddenGroup (w, 5, 0, NULL);
2724     b = PushButton (g, "Find", FindInGeneralText);
2725     SetObjectExtra (b, tfp, NULL);
2726     tfp->find = DialogText (g, "", 10, NULL);
2727     if (repopulate_func != NULL)
2728     {
2729       rp = (RepopulateViewerPtr) MemNew (sizeof (RepopulateViewerData));
2730       if (rp != NULL)
2731       {
2732         rp->repopulate_func = repopulate_func;
2733         rp->repopulate_data = repopulate_data;
2734         rp->free_data_func = free_data_func;
2735         rp->tfp = tfp;
2736         rp->fnt = fnt;
2737         b = PushButton (g, "Repopulate", RepopulateViewer);
2738         SetObjectExtra (b, rp, CleanupRepopulateViewer);
2739       }
2740     }
2741   }
2742 
2743   if (useScrollText) {
2744     tfp->text = ScrollText (w, (pixwidth + stdCharWidth - 1) / stdCharWidth,
2745                             (pixheight + stdLineHeight - 1) / stdLineHeight,
2746                             fnt, FALSE, NULL);
2747     SetObjectExtra (tfp->text, tfp, NULL);
2748     RealizeWindow (w);
2749     if (! FileToScrollText (tfp->text, path)) {
2750       /* SetTitle (tfp->text, "(Text is too large to be displayed in this control.)"); */
2751       Remove (w);
2752       LaunchGeneralTextViewerEx (path, title, FALSE,
2753                                  repopulate_func, repopulate_data, free_data_func);
2754       return;
2755     }
2756   } else {
2757     tfp->doc = DocumentPanel (w, pixwidth, pixheight);
2758     SetObjectExtra (tfp->doc, tfp, NULL);
2759     RealizeWindow (w);
2760     txtColFmt.pixWidth = screenRect.right - screenRect.left;
2761     txtColFmt.pixInset = 8;
2762     DisplayFancy (tfp->doc, path, &txtParFmt, &txtColFmt, fnt, 0);
2763     /* document.c: SaveTableItem does not strip preceeding tabs if tabCount is 0 */
2764   }
2765   Show (w);
2766   Select (w);
2767   Update ();
2768 }
2769 
2770 extern void LaunchGeneralTextViewerWithRepopulate 
2771 (CharPtr                path,
2772  CharPtr                title, 
2773  Nlm_RepopulateViewer   repopulate_func,
2774  Pointer                repopulate_data,
2775  Nlm_RepopulateDataFree free_data_func)
2776 {
2777   TextViewProcsPtr tvpp;
2778 
2779   tvpp = (TextViewProcsPtr) GetAppProperty ("TextDisplayForm");
2780   if (tvpp != NULL && tvpp->useScrollText) {
2781     LaunchGeneralTextViewerEx (path, title, TRUE, 
2782                                repopulate_func, repopulate_data, free_data_func);
2783   } else {
2784     LaunchGeneralTextViewerEx (path, title, FALSE, 
2785                                repopulate_func, repopulate_data, free_data_func);
2786   }
2787 }
2788 
2789 extern void LaunchGeneralTextViewer (CharPtr path, CharPtr title)
2790 
2791 {
2792   TextViewProcsPtr tvpp;
2793 
2794   tvpp = (TextViewProcsPtr) GetAppProperty ("TextDisplayForm");
2795   if (tvpp != NULL && tvpp->useScrollText) {
2796     LaunchGeneralTextViewerEx (path, title, TRUE, NULL, NULL, NULL);
2797   } else {
2798     LaunchGeneralTextViewerEx (path, title, FALSE, NULL, NULL, NULL);
2799   }
2800 }
2801 
2802 extern void LaunchAsnTextViewer (Pointer from, AsnWriteFunc writefunc, CharPtr title)
2803 
2804 {
2805   AsnIoPtr  aip;
2806   Char      path [PATH_MAX];
2807 
2808   if (from == NULL || writefunc == NULL) return;
2809   if (StringHasNoText (title)) {
2810     title = "General ASN.1 Text Viewer";
2811   }
2812 
2813   TmpNam (path);
2814   aip = AsnIoOpen (path, "w");
2815   if (aip != NULL) {
2816     (*writefunc) (from, aip, NULL);
2817     AsnIoClose (aip);
2818     LaunchGeneralTextViewer (path, title);
2819   }
2820   FileRemove (path);
2821 }
2822 
2823 #ifndef WIN_MAC
2824 extern void CreateStdEditorFormMenus (WindoW w)
2825 
2826 {
2827   BaseFormPtr   bfp;
2828   MenU          m;
2829 
2830   bfp = (BaseFormPtr) GetObjectExtra (w);
2831   if (bfp != NULL) {
2832     m = PulldownMenu (w, "File");
2833     if (bfp->importform != NULL || bfp->exportform != NULL) {
2834       if (bfp->importform != NULL) {
2835         FormCommandItem (m, "Import...", bfp, VIB_MSG_IMPORT);
2836       }
2837       if (bfp->exportform != NULL) {
2838         FormCommandItem (m, "Export...", bfp, VIB_MSG_EXPORT);
2839       }
2840       SeparatorItem (m);
2841     }
2842     FormCommandItem (m, "Close", bfp, VIB_MSG_CLOSE);
2843     m = PulldownMenu (w, "Edit");
2844     FormCommandItem (m, CUT_MENU_ITEM, bfp, VIB_MSG_CUT);
2845     FormCommandItem (m, COPY_MENU_ITEM, bfp, VIB_MSG_COPY);
2846     FormCommandItem (m, PASTE_MENU_ITEM, bfp, VIB_MSG_PASTE);
2847     FormCommandItem (m, CLEAR_MENU_ITEM, bfp, VIB_MSG_DELETE);
2848   }
2849 }
2850 #endif
2851 
2852 static Boolean DlgutilGetLowestStackSeqEntry (GatherContextPtr gcp)
2853 
2854 {
2855   BaseFormPtr  bfp;
2856   Int2         i;
2857 
2858   if (gcp == NULL) return TRUE;
2859   bfp = (BaseFormPtr) gcp->userdata;
2860   if (bfp == NULL) return TRUE;
2861   if (gcp->gatherstack != NULL && gcp->numstack > 0) {
2862     for (i = 0; i < gcp->numstack; i++) {
2863       if (gcp->gatherstack [i].itemtype == OBJ_BIOSEQ ||
2864           gcp->gatherstack [i].itemtype == OBJ_BIOSEQSET) {
2865         bfp->input_itemID = gcp->gatherstack [i].itemID;
2866         bfp->input_itemtype = gcp->gatherstack [i].itemtype;
2867       }
2868     }
2869   }
2870   return FALSE;
2871 }
2872 
2873 extern Boolean SetClosestParentIfDuplicating (BaseFormPtr bfp)
2874 
2875 {
2876   Uint4              itemID;
2877   Uint2              itemtype;
2878   StdEditorProcsPtr  sepp;
2879 
2880   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
2881   if (bfp == NULL || sepp == NULL || (! sepp->duplicateExisting)) return FALSE;
2882   itemID = bfp->input_itemID;
2883   itemtype = bfp->input_itemtype;
2884   GatherItem (bfp->input_entityID, bfp->input_itemID, bfp->input_itemtype,
2885               (Pointer) bfp, DlgutilGetLowestStackSeqEntry);
2886   if (itemID == bfp->input_itemID && itemtype == bfp->input_itemtype) {
2887     return FALSE;
2888   }
2889   return TRUE;
2890 }
2891 
2892 /*****************************************************************************
2893 *
2894 *   Bond and Point SeqLoc dialogs
2895 *
2896 *****************************************************************************/
2897 
2898 typedef struct pointpage {
2899   DIALOG_MESSAGE_BLOCK
2900   TexT               point;
2901   Int2               count;
2902   SeqEntryPtr        PNTR bsptr;
2903   EnumFieldAssoc     PNTR alist;
2904   PopuP              strand;
2905   PopuP              seqIdx;
2906   Boolean            nucsOK;
2907   Boolean            protsOK;
2908   Boolean            showIdTags;
2909 } PointPage, PNTR PointPagePtr;
2910 
2911 typedef struct bondpage {
2912   DIALOG_MESSAGE_BLOCK
2913   DialoG             pointA;
2914   DialoG             pointB;
2915 } BondPage, PNTR BondPagePtr;
2916 
2917 static void FillInPointProducts (SeqEntryPtr sep, Pointer mydata,
2918                                  Int4 index, Int2 indent)
2919 
2920 {
2921   BioseqPtr     bsp;
2922   PointPagePtr  ppp;
2923 
2924   if (sep != NULL && mydata != NULL && sep->choice == 1) {
2925     ppp = (PointPagePtr) mydata;
2926     bsp = (BioseqPtr) sep->data.ptrvalue;
2927     if (bsp != NULL) {
2928       if ((ppp->nucsOK && ISA_na (bsp->mol)) ||
2929           (ppp->protsOK && ISA_aa (bsp->mol))) {
2930         ppp->count++;
2931         ppp->bsptr [ppp->count] = sep;
2932       }
2933     }
2934   }
2935 }
2936 
2937 static ENUM_ALIST(strand_alist)
2938 {" ",             Seq_strand_unknown},  /* 0 */
2939 {"Plus",          Seq_strand_plus},     /* 1 */
2940 {"Minus",         Seq_strand_minus},    /* 2 */
2941 /*
2942 {"Both",          Seq_strand_both},
2943 {"Reverse",       Seq_strand_both_rev},
2944 */
2945 {"Other",         Seq_strand_other},    /* 255 */
2946 END_ENUM_ALIST
2947 
2948 static void SeqPntPtrToPointPage (DialoG d, Pointer data)
2949 
2950 
2951 {
2952   BioseqPtr     bsp;
2953   Int2          j;
2954   PointPagePtr  ppp;
2955   SeqEntryPtr   sep;
2956   Int2          seq;
2957   SeqPntPtr     spp;
2958   Char          str [16];
2959   Uint1         strand;
2960 
2961   ppp = (PointPagePtr) GetObjectExtra (d);
2962   if (ppp == NULL) return;
2963   spp = (SeqPntPtr) data;
2964   if (spp != NULL) {
2965     sprintf (str, "%ld", (long) (spp->point + 1));
2966     SafeSetTitle (ppp->point, str);
2967     seq = 0;
2968     strand = 0;
2969     bsp = BioseqFind (spp->id);
2970     if (bsp != NULL) {
2971       strand = spp->strand;
2972       if (strand > Seq_strand_both_rev && strand != Seq_strand_other) {
2973         strand = Seq_strand_unknown;
2974       }
2975       if (ppp->bsptr != NULL) {
2976         for (j = 1; j <= ppp->count && seq == 0; j++) {
2977           sep = ppp->bsptr [j];
2978           if (sep != NULL && sep->choice == 1) {
2979             if (bsp == (BioseqPtr) sep->data.ptrvalue) {
2980               seq = j;
2981             }
2982           }
2983         }
2984       }
2985     }
2986     SetEnumPopup (ppp->strand, strand_alist, (UIEnum) strand);
2987     SetEnumPopup (ppp->seqIdx, ppp->alist, (UIEnum) seq);
2988   } else {
2989     SafeSetTitle (ppp->point, "");
2990     SafeSetValue (ppp->strand, 0);
2991     SafeSetValue (ppp->seqIdx, 0);
2992   }
2993 }
2994 
2995 static Pointer PointPageToSeqPntPtr (DialoG d)
2996 
2997 {
2998   BioseqPtr     bsp;
2999   PointPagePtr  ppp;
3000   SeqEntryPtr   sep;
3001   UIEnum        seq;
3002   SeqPntPtr     spp;
3003   Char          str [16];
3004   UIEnum        strand;
3005   Int4          val;
3006 
3007   ppp = (PointPagePtr) GetObjectExtra (d);
3008   if (ppp == NULL) return NULL;
3009   spp = NULL;
3010   GetTitle (ppp->point, str, sizeof (str) - 1);
3011   if (StrToLong (str, &val) && val > 0) {
3012     if (GetEnumPopup (ppp->seqIdx, ppp->alist, &seq) &&
3013         seq > 0 && seq <= ppp->count) {
3014       spp = SeqPntNew ();
3015       if (spp != NULL) {
3016         spp->point = val - 1;
3017         if (GetEnumPopup (ppp->strand, strand_alist, &strand)) {
3018           spp->strand = (Uint1) strand;
3019         }
3020         sep = ppp->bsptr [(Int2) seq];
3021         if (sep != NULL && sep->choice == 1) {
3022           bsp = (BioseqPtr) sep->data.ptrvalue;
3023           if (bsp != NULL) {
3024             spp->id = SeqIdStripLocus (SeqIdDup (SeqIdFindBest (bsp->id, 0)));
3025           }
3026         }
3027       }
3028     }
3029   }
3030   return (Pointer) spp;
3031 }
3032 
3033 static void PointEditorMessage (DialoG d, Int2 mssg)
3034 
3035 {
3036   PointPagePtr  ppp;
3037 
3038   ppp = (PointPagePtr) GetObjectExtra (d);
3039   if (ppp != NULL) {
3040     if (mssg == VIB_MSG_INIT) {
3041       SeqPntPtrToPointPage (d, NULL);
3042     } else if (mssg == VIB_MSG_ENTER) {
3043       Select (ppp->point);
3044     } else if (mssg == VIB_MSG_RESET) {
3045     }
3046   }
3047 }
3048 
3049 static void CleanupPointPage (GraphiC g, VoidPtr data)
3050 
3051 {
3052   Int2          j;
3053   PointPagePtr  ppp;
3054 
3055   ppp = (PointPagePtr) data;
3056   if (ppp != NULL) {
3057     MemFree (ppp->bsptr);
3058     if (ppp->alist != NULL) {
3059       for (j = 0; j <= ppp->count + 1; j++) {
3060         MemFree (ppp->alist [j].name);
3061       }
3062     }
3063     MemFree (ppp->alist);
3064   }
3065   MemFree (data);
3066 }
3067 
3068 static DialoG CreatePointEditorDialog (GrouP h, CharPtr title, SeqEntryPtr sep,
3069                                        Boolean nucsOK, Boolean protsOK)
3070 
3071 {
3072   BioseqPtr     bsp;
3073   Int4          count;
3074   GrouP         f;
3075   Int2          j;
3076   GrouP         m;
3077   GrouP         p;
3078   PointPagePtr  ppp;
3079   CharPtr       ptr;
3080   GrouP         s;
3081   Boolean       showIdTags;
3082   SeqIdPtr      sip;
3083   Char          str [128];
3084 
3085   p = HiddenGroup (h, 1, 0, NULL);
3086   SetGroupSpacing (p, 10, 10);
3087 
3088   ppp = (PointPagePtr) MemNew (sizeof (PointPage));
3089   if (ppp != NULL) {
3090 
3091     SetObjectExtra (p, ppp, CleanupPointPage);
3092     ppp->dialog = (DialoG) p;
3093     ppp->todialog = SeqPntPtrToPointPage;
3094     ppp->fromdialog = PointPageToSeqPntPtr;
3095     ppp->dialogmessage = PointEditorMessage;
3096     ppp->testdialog = NULL;
3097     ppp->importdialog = NULL;
3098     ppp->exportdialog = NULL;
3099 
3100     if (title != NULL && title [0] != '\0') {
3101       s = NormalGroup (p, 0, -2, title, systemFont, NULL);
3102     } else {
3103       s = HiddenGroup (p, 0, -2, NULL);
3104     }
3105     m = HiddenGroup (s, -1, 0, NULL);
3106     /*
3107     SetGroupSpacing (m, 10, 10);
3108     */
3109 
3110     ppp->nucsOK = nucsOK;
3111     ppp->protsOK = protsOK;
3112     ppp->showIdTags = FALSE;
3113     ppp->count = 0;
3114 
3115     if (sep != NULL) {
3116       count = SeqEntryCount (sep);
3117       count += 4;
3118       ppp->bsptr = MemNew (sizeof (BioseqPtr) * (size_t) count);
3119       ppp->alist = MemNew (sizeof (EnumFieldAssoc) * (size_t) count);
3120       ppp->count = 0;
3121 
3122       if (ppp->bsptr != NULL && ppp->alist != NULL) {
3123         SeqEntryExplore (sep, (Pointer) ppp, FillInPointProducts);
3124         j = 0;
3125         ppp->alist [j].name = StringSave ("     ");
3126         ppp->alist [j].value = (UIEnum) 0;
3127         for (j = 1; j <= ppp->count; j++) {
3128           sep = ppp->bsptr [j];
3129           if (sep != NULL && sep->choice == 1 && sep->data.ptrvalue != NULL) {
3130             bsp = (BioseqPtr) sep->data.ptrvalue;
3131             sip = SeqIdFindWorst (bsp->id);
3132             SeqIdWrite (sip, str, PRINTID_REPORT, sizeof (str));
3133             ptr = StringChr (str, '|');
3134             showIdTags = FALSE;
3135             if (ptr == NULL) {
3136               ptr = str;
3137             } else if (showIdTags) {
3138               ptr = str;
3139             } else {
3140               ptr++;
3141             }
3142             ppp->alist [j].name = StringSave (ptr);
3143             ppp->alist [j].value = (UIEnum) j;
3144           }
3145         }
3146         j = ppp->count + 1;
3147         ppp->alist [j].name = NULL;
3148         ppp->alist [j].value = (UIEnum) 0;
3149       }
3150 
3151     } else {
3152       ppp->alist = MemNew (sizeof (EnumFieldAssoc) * (size_t) 4);
3153       if (ppp->alist != NULL) {
3154         j = 0;
3155         ppp->alist [j].name = StringSave ("     ");
3156         ppp->alist [j].value = (UIEnum) 0;
3157         j = 1;
3158         ppp->alist [j].name = NULL;
3159         ppp->alist [j].value = (UIEnum) 0;
3160 
3161       }
3162     }
3163 
3164     f = HiddenGroup (m, 6, 0, NULL);
3165     /*StaticPrompt (f, "Point", 0, dialogTextHeight, programFont, 'l');*/
3166     ppp->point = DialogText (f, "", 5, NULL);
3167     if (nucsOK) {
3168       /*StaticPrompt (f, "Strand", 0, popupMenuHeight, programFont, 'c');*/
3169       ppp->strand = PopupList (f, TRUE, NULL);
3170       InitEnumPopup (ppp->strand, strand_alist, NULL);
3171     }
3172     /*StaticPrompt (f, "SeqID", 0, popupMenuHeight, programFont, 'l');*/
3173     ppp->seqIdx = PopupList (f, TRUE, NULL);
3174     InitEnumPopup (ppp->seqIdx, ppp->alist, NULL);
3175   }
3176 
3177   return (DialoG) p;
3178 }
3179 
3180 static void SeqLocPtrToBondPage (DialoG d, Pointer data)
3181 
3182 
3183 {
3184   BondPagePtr  bpp;
3185   SeqBondPtr   sbp;
3186   SeqIdPtr     sip;
3187   SeqLocPtr    slp;
3188   SeqPnt       sqp;
3189 
3190   bpp = (BondPagePtr) GetObjectExtra (d);
3191   if (bpp == NULL) return;
3192   slp = (SeqLocPtr) data;
3193   if (slp != NULL) {
3194     if (slp->choice == SEQLOC_BOND) {
3195       sbp = (SeqBondPtr) slp->data.ptrvalue;
3196       if (sbp != NULL) {
3197         PointerToDialog (bpp->pointA, (Pointer) sbp->a);
3198         PointerToDialog (bpp->pointB, (Pointer) sbp->b);
3199       }
3200     } else {
3201       sip = SeqLocId (slp);
3202       if (sip != NULL) {
3203         sqp.strand = SeqLocStrand (slp);
3204         sqp.id = sip;
3205         sqp.point = SeqLocStart (slp);
3206         PointerToDialog (bpp->pointA, (Pointer) &sqp);
3207         sqp.point = SeqLocStop (slp);
3208         PointerToDialog (bpp->pointB, (Pointer) &sqp);
3209       }
3210     }
3211   }
3212 }
3213 
3214 static Pointer BondPageToSeqLocPtr (DialoG d)
3215 
3216 {
3217   BondPagePtr  bpp;
3218   SeqBondPtr   sbp;
3219   SeqLocPtr    slp;
3220 
3221   bpp = (BondPagePtr) GetObjectExtra (d);
3222   if (bpp == NULL) return NULL;
3223   slp = NULL;
3224   sbp = SeqBondNew ();
3225   if (sbp != NULL) {
3226     slp = ValNodeNew (NULL);
3227     if (slp != NULL) {
3228       slp->choice = SEQLOC_BOND;
3229       slp->data.ptrvalue = (Pointer) sbp;
3230       sbp->a = DialogToPointer (bpp->pointA);
3231       sbp->b = DialogToPointer (bpp->pointB);
3232     } else {
3233       SeqBondFree (sbp);
3234     }
3235   }
3236   return (Pointer) slp;
3237 }
3238 
3239 static void BondEditorMessage (DialoG d, Int2 mssg)
3240 
3241 {
3242   BondPagePtr  bpp;
3243 
3244   bpp = (BondPagePtr) GetObjectExtra (d);
3245   if (bpp != NULL) {
3246     if (mssg == VIB_MSG_INIT) {
3247       SeqLocPtrToBondPage (d, NULL);
3248     } else if (mssg == VIB_MSG_ENTER) {
3249       SendMessageToDialog (bpp->pointA, VIB_MSG_ENTER);
3250     } else if (mssg == VIB_MSG_RESET) {
3251     }
3252   }
3253 }
3254 
3255 extern DialoG CreateBondEditorDialog (GrouP h, CharPtr title, SeqEntryPtr sep);
3256 
3257 extern DialoG CreateBondEditorDialog (GrouP h, CharPtr title, SeqEntryPtr sep)
3258 
3259 {
3260   BondPagePtr  bpp;
3261   GrouP        f;
3262   GrouP        m;
3263   GrouP        p;
3264   GrouP        s;
3265 
3266   p = HiddenGroup (h, 1, 0, NULL);
3267   SetGroupSpacing (p, 10, 10);
3268 
3269   bpp = (BondPagePtr) MemNew (sizeof (BondPage));
3270   if (bpp != NULL) {
3271 
3272     SetObjectExtra (p, bpp, StdCleanupExtraProc);
3273     bpp->dialog = (DialoG) p;
3274     bpp->todialog = SeqLocPtrToBondPage;
3275     bpp->fromdialog = BondPageToSeqLocPtr;
3276     bpp->dialogmessage = BondEditorMessage;
3277     bpp->testdialog = NULL;
3278     bpp->importdialog = NULL;
3279     bpp->exportdialog = NULL;
3280 
3281     if (title != NULL && title [0] != '\0') {
3282       s = NormalGroup (p, 0, -2, title, systemFont, NULL);
3283     } else {
3284       s = HiddenGroup (p, 0, -2, NULL);
3285     }
3286     m = HiddenGroup (s, -1, 0, NULL);
3287     /*
3288     SetGroupSpacing (m, 10, 10);
3289     */
3290 
3291     f = HiddenGroup (m, 2, 0, NULL);
3292     StaticPrompt (f, "From", 0, popupMenuHeight, programFont, 'l');
3293     bpp->pointA = CreatePointEditorDialog (f, NULL, sep, FALSE, TRUE);
3294     StaticPrompt (f, "(To)", 0, popupMenuHeight, programFont, 'l');
3295     bpp->pointB = CreatePointEditorDialog (f, NULL, sep, FALSE, TRUE);
3296   }
3297 
3298   return (DialoG) p;
3299 }
3300 
3301 void GetRidOfEmptyFeatsDescStrings (Uint2 entityID, SeqEntryPtr sep)
3302 
3303 {
3304   if (entityID < 1 && sep == NULL) return;
3305   if (entityID > 0 && sep == NULL) {
3306     sep = GetTopSeqEntryForEntityID (entityID);
3307   }
3308   if (sep == NULL) return;
3309   SeqEntryExplore (sep, NULL, GetRidOfEmptyFeatsDescCallback);
3310 }
3311 
3312 extern Int2 LIBCALLBACK StdVibrantEditorMsgFunc (OMMsgStructPtr ommsp)
3313 
3314 {
3315   BaseFormPtr    bfp;
3316   OMUserDataPtr  omudp;
3317 
3318   omudp = (OMUserDataPtr)(ommsp->omuserdata);
3319   if (omudp == NULL) return OM_MSG_RET_ERROR;
3320   bfp = (BaseFormPtr) omudp->userdata.ptrvalue;
3321   if (bfp == NULL) return OM_MSG_RET_ERROR;
3322   switch (ommsp->message) {
3323     case OM_MSG_DEL:
3324       Remove (bfp->form);
3325       Update ();
3326       break;
3327     default :
3328       break;
3329   }
3330   return OM_MSG_RET_OK;
3331 }
3332 
3333 /* launch url section */
3334 
3335 NLM_EXTERN void LaunchEntrezURL (CharPtr database, Int4 uid, CharPtr format)
3336 
3337 {
3338 #ifdef WIN_MOTIF
3339   NS_Window  window = NULL;
3340 #endif
3341 
3342   Char  url [256];
3343 
3344   if (uid < 1 || StringHasNoText (database) || StringHasNoText (format)) return;
3345   sprintf (url,
3346            "http://www.ncbi.nlm.nih.gov:80/entrez/query.fcgi?cmd=Retrieve&db=%s&list_uids=%ld&dopt=%s",
3347             database, (long) uid, format);
3348 
3349 #ifdef WIN_MAC
3350   Nlm_SendURLAppleEvent (url, "MOSS", NULL);
3351 #endif
3352 #ifdef WIN_MSWIN
3353   if (! Nlm_MSWin_OpenDocument (url)) {
3354     Message (MSG_POST, "Unable to launch browser");
3355   }
3356 #endif
3357 #ifdef WIN_MOTIF
3358   if (! NS_OpenURL (&window, url, NULL, TRUE)) {
3359     Message (MSG_POST, "Unable to launch browser");
3360   }
3361   NS_WindowFree (window);
3362 #endif
3363 }
3364 
3365 extern void ModalAcceptButton (ButtoN b)
3366 {
3367   ModalAcceptCancelPtr acp;
3368   
3369   acp = (ModalAcceptCancelPtr) GetObjectExtra (b);
3370   if (acp != NULL)
3371   {
3372     acp->accepted = TRUE;
3373   }
3374 }
3375 
3376 extern void ModalCancelButton (ButtoN b)
3377 {
3378   ModalAcceptCancelPtr acp;
3379   
3380   acp = (ModalAcceptCancelPtr) GetObjectExtra (b);
3381   if (acp != NULL)
3382   {
3383     acp->cancelled = TRUE;
3384   }
3385 }
3386 
3387 extern void ModalThirdOptionButton (ButtoN b)
3388 {
3389   ModalAcceptCancelPtr acp;
3390   
3391   acp = (ModalAcceptCancelPtr) GetObjectExtra (b);
3392   if (acp != NULL)
3393   {
3394     acp->third_option = TRUE;
3395   }
3396 }
3397 
3398 
3399 NLM_EXTERN Int4 
3400 ThreeOptionsDlg
3401 (CharPtr title_txt,
3402  CharPtr explain_txt,
3403  CharPtr opt1,
3404  CharPtr opt2,
3405  CharPtr opt3)
3406 {
3407   WindoW w;
3408   GrouP  h, c;
3409   ButtoN b;
3410   GrouP  p;
3411   ModalAcceptCancelData acd;
3412   
3413   
3414   w = MovableModalWindow (-20, -13, -10, -10, title_txt, NULL);
3415   h = HiddenGroup(w, -1, 0, NULL);
3416   SetGroupSpacing (h, 10, 10);
3417 
3418   p = MultiLinePrompt (h, explain_txt, 300, programFont);
3419     
3420   c = HiddenGroup (h, 3, 0, NULL);
3421   b = PushButton (c, opt1, ModalAcceptButton);
3422   SetObjectExtra (b, &acd, NULL);
3423   b = PushButton (c, opt2, ModalCancelButton);
3424   SetObjectExtra (b, &acd, NULL);
3425   
3426   if (!StringHasNoText (opt3)) {
3427     b = PushButton (c, opt3, ModalThirdOptionButton);
3428     SetObjectExtra (b, &acd, NULL);
3429   }
3430   
3431   AlignObjects (ALIGN_CENTER, (HANDLE) p,
3432                               (HANDLE) c, 
3433                               NULL);
3434 
3435   Show (w);
3436   Select (w);
3437   
3438   acd.cancelled = FALSE;
3439   acd.third_option = FALSE;
3440   acd.accepted = FALSE;
3441   while (!acd.accepted && ! acd.cancelled && !acd.third_option)
3442   {
3443     ProcessExternalEvent ();
3444     Update ();
3445   }
3446   ProcessAnEvent ();
3447   Remove (w);
3448   
3449   if (acd.accepted)
3450   {
3451     return 1;
3452   }
3453   else if (acd.cancelled)
3454   {
3455     return 2;
3456   }
3457   else
3458   {
3459     return 3;
3460   }
3461 }
3462 
3463 
3464 typedef struct tabledisplay 
3465 {
3466   DIALOG_MESSAGE_BLOCK
3467   PaneL panel;
3468   ValNodePtr row_list;
3469   Int4 frozen_header;
3470   Int4 frozen_left;
3471   Int4 table_inset;
3472   Int4 char_width;
3473   Int4 descent;
3474   FonT display_font;
3475   TableDisplayDblClick dbl_click;
3476   Pointer dbl_click_data;
3477   TableDisplayLeftInRed left_in_red;
3478   Pointer left_in_red_data;
3479 } TableDisplayData, PNTR TableDisplayPtr;
3480 
3481 extern ValNodePtr FreeTableDisplayRowList (ValNodePtr row_list)
3482 {
3483   ValNodePtr row_vnp, column_list;
3484   
3485   if (row_list != NULL)
3486   {
3487     /* free table text */
3488     for (row_vnp = row_list; row_vnp != NULL; row_vnp = row_vnp->next)
3489     {
3490       column_list = (ValNodePtr) row_vnp->data.ptrvalue;
3491       row_vnp->data.ptrvalue = ValNodeFreeData (column_list);
3492     }
3493     row_list = ValNodeFree (row_list);
3494   }
3495   return row_list;
3496 }
3497 
3498 extern void PrintTableDisplayRowListToFile (ValNodePtr row_list, FILE *fp)
3499 {
3500   ValNodePtr row_vnp, col_vnp, column_list;
3501   CharPtr    txt_val;
3502   
3503   if (row_list == NULL || fp == NULL)
3504   {
3505     return;
3506   }
3507   
3508   for (row_vnp = row_list; row_vnp != NULL; row_vnp = row_vnp->next)
3509   {
3510     column_list = (ValNodePtr) row_vnp->data.ptrvalue;
3511     for (col_vnp = column_list; col_vnp != NULL; col_vnp = col_vnp->next)
3512     {
3513       txt_val = (CharPtr) col_vnp->data.ptrvalue;
3514       if (!StringHasNoText (txt_val))
3515       {
3516         fprintf (fp, "%s", txt_val);
3517       }
3518       if (col_vnp->next == NULL)
3519       {
3520         fprintf (fp, "\n");
3521       }
3522       else
3523       {
3524         fprintf (fp, "\t");
3525       }
3526     }
3527   }
3528 }
3529 
3530 static ValNodePtr ValNodeStringListCopy (ValNodePtr orig_list)
3531 {
3532   ValNodePtr new_list = NULL;
3533   
3534   if (orig_list == NULL)
3535   {
3536     return NULL;
3537   }
3538   
3539   new_list = ValNodeNew (NULL);
3540   new_list->choice = orig_list->choice;
3541   new_list->data.ptrvalue = StringSave (orig_list->data.ptrvalue);
3542   new_list->next = ValNodeStringListCopy (orig_list->next);
3543   return new_list;
3544 }
3545 
3546 extern ValNodePtr CopyTableDisplayRowList (ValNodePtr row_list)
3547 {
3548   ValNodePtr new_row_list = NULL;
3549   
3550   if (row_list == NULL)
3551   {
3552     return NULL; 
3553   }
3554   
3555   new_row_list = ValNodeNew (NULL);
3556   new_row_list->choice = row_list->choice;
3557   new_row_list->data.ptrvalue = ValNodeStringListCopy (row_list->data.ptrvalue);
3558   new_row_list->next = CopyTableDisplayRowList (row_list->next);
3559   return new_row_list;
3560 }
3561 
3562 static void CleanupTableDisplayDialog (GraphiC g, VoidPtr data)
3563 {
3564   TableDisplayPtr dlg;
3565 
3566   dlg = (TableDisplayPtr) data;
3567   if (dlg != NULL) {
3568     dlg->row_list = FreeTableDisplayRowList (dlg->row_list);
3569   }
3570   StdCleanupExtraProc (g, data);
3571 }
3572 
3573 static void UpdateTableDisplayDialogScrollBars (TableDisplayPtr dlg)
3574 {
3575   BaR  sb_vert;
3576   BaR  sb_horiz;
3577   Int4 start_row, start_col;
3578   Int4 num_rows, num_columns, visible_rows;
3579   Int4 new_vmax, new_hmax, old_vmax, old_hmax;
3580   RecT r;
3581   Int4 x, y;
3582   
3583   if (dlg == NULL)
3584   {
3585     return;
3586   }
3587   
3588   sb_vert  = GetSlateVScrollBar ((SlatE) dlg->panel);
3589   sb_horiz = GetSlateHScrollBar ((SlatE) dlg->panel);
3590   
3591   start_row = GetBarValue (sb_vert) + dlg->frozen_header;
3592   start_col = GetBarValue (sb_horiz) + dlg->frozen_left;
3593     
3594   if (dlg->row_list == NULL)
3595   {
3596     num_rows = 0;
3597     num_columns = 0;
3598   }
3599   else
3600   {
3601     num_rows = ValNodeLen (dlg->row_list);
3602     num_columns = ValNodeLen (dlg->row_list->data.ptrvalue);
3603   }
3604 
3605   ObjectRect (dlg->panel, &r);
3606   InsetRect (&r, dlg->table_inset, dlg->table_inset);
3607   x = r.left + 1;
3608   y = r.top + stdLineHeight;
3609     
3610   visible_rows = (r.bottom - r.top - 2 * dlg->table_inset) / stdLineHeight - dlg->frozen_header;
3611   new_vmax = num_rows - visible_rows - 1;
3612   new_hmax = num_columns - dlg->frozen_left - 1;
3613   if (new_vmax < 0)
3614   {
3615     new_vmax = 0;
3616   }
3617   if (new_hmax < 0)
3618   {
3619     new_hmax = 0;
3620   }
3621   old_vmax = GetBarMax (sb_vert);
3622   old_hmax = GetBarMax (sb_horiz);
3623   
3624   if (old_vmax != new_vmax)
3625   {
3626     CorrectBarMax (sb_vert, new_vmax);
3627     if (start_row > new_vmax + dlg->frozen_header)
3628     {
3629       start_row = new_vmax + dlg->frozen_header;
3630     }
3631     CorrectBarValue (sb_vert, start_row - dlg->frozen_header);
3632     CorrectBarPage (sb_vert, 1, 1);
3633   }
3634   
3635   if (old_hmax != new_hmax)
3636   {
3637     CorrectBarMax (sb_horiz, new_hmax);
3638     if (start_col > new_hmax + dlg->frozen_left)
3639     {
3640       start_col = new_hmax + dlg->frozen_left;
3641     }
3642     CorrectBarValue (sb_horiz, start_col - dlg->frozen_left);
3643     CorrectBarPage (sb_horiz, 1, 1);
3644   }  
3645 }
3646 
3647 static void RowsToTableDisplayDialog (DialoG d, Pointer userdata)
3648 {
3649   TableDisplayPtr dlg;
3650   RecT            r;
3651     WindoW          temport;
3652 
3653   dlg = (TableDisplayPtr) GetObjectExtra (d);
3654   if (dlg == NULL)
3655   {
3656     return;
3657   }
3658   
3659   dlg->row_list = FreeTableDisplayRowList (dlg->row_list);
3660   dlg->row_list = CopyTableDisplayRowList (userdata);
3661   UpdateTableDisplayDialogScrollBars (dlg);
3662   temport = SavePort (dlg->panel);
3663   Select (dlg->panel);
3664   ObjectRect (dlg->panel, &r);
3665   InvalRect (&r);  
3666   Update ();
3667   RestorePort (temport);
3668 }
3669 
3670 static Pointer TableDisplayDialogToRows (DialoG d)
3671 {
3672   TableDisplayPtr dlg;
3673 
3674   dlg = (TableDisplayPtr) GetObjectExtra (d);
3675   if (dlg == NULL)
3676   {
3677     return NULL;
3678   }
3679   
3680   return CopyTableDisplayRowList (dlg->row_list);
3681 }
3682 
3683 static Int4 
3684 PrepareTableDisplayTextBuffer 
3685 (CharPtr buf,
3686  Int4    remaining_chars_in_row,
3687  Int4    col_width,
3688  CharPtr data)
3689 {
3690   Uint4 chars_to_paint = 0;
3691   if (buf == NULL)
3692   {
3693     return 0;
3694   }
3695   
3696   if (remaining_chars_in_row < col_width)
3697   {
3698     chars_to_paint = remaining_chars_in_row;
3699     StringNCpy (buf, data, chars_to_paint);
3700     buf [chars_to_paint] = 0;
3701   }
3702   else
3703   {
3704     chars_to_paint = col_width;
3705     StringNCpy (buf, data, chars_to_paint);
3706     buf [chars_to_paint] = 0;
3707     if (StringLen (data) > chars_to_paint && chars_to_paint > 2)
3708     {
3709       buf [chars_to_paint - 1] = '.';
3710       buf [chars_to_paint - 2] = '.';
3711       buf [chars_to_paint - 3] = '.';
3712     }
3713   }
3714   return chars_to_paint;
3715 }
3716 
3717 static void DrawTableDisplayLine (Int4 x, Int4 y, 
3718  ValNodePtr header_row,
3719  ValNodePtr data_row,
3720  CharPtr    buf,
3721  Int4       row_length,
3722  Int4       frozen_left,
3723  Int4       start_col,
3724  Int4       char_width,
3725  Int4       descent,
3726  Boolean    left_in_red)
3727 {
3728   ValNodePtr header_vnp, data_vnp;
3729   Int4       x_offset, chars_to_paint, col_num;
3730   PoinT      pt1, pt2;
3731   RecT       rct;
3732   
3733   /* draw left margin */
3734   
3735   for (header_vnp = header_row, data_vnp = data_row, x_offset = 0, col_num = 0;
3736        header_vnp != NULL && data_vnp != NULL && x_offset < row_length && col_num < frozen_left;
3737        header_vnp = header_vnp->next, data_vnp = data_vnp->next, col_num++)
3738   {
3739     Gray ();
3740     InvertColors ();
3741     if (left_in_red)
3742     {
3743       Red ();
3744     }
3745     else
3746     {
3747       White ();
3748     }
3749     chars_to_paint = PrepareTableDisplayTextBuffer (buf, 
3750                                    (row_length - x_offset) / char_width,
3751                                    header_vnp->choice,
3752                                    data_vnp->data.ptrvalue);
3753         
3754     LoadRect (&rct, x + x_offset, y + descent,
3755               x + x_offset + (chars_to_paint + 2) * char_width, 
3756               y - stdLineHeight + descent);
3757     EraseRect (&rct);
3758 
3759     PaintStringEx ( (CharPtr)buf, x + x_offset, y);
3760     x_offset += (chars_to_paint + 2) * char_width;
3761     InvertColors ();
3762     Black ();
3763   }
3764   
3765   if (frozen_left > 0)
3766   {
3767     pt1.x = x + x_offset - 1;
3768     pt1.y = y;
3769     pt2.x = x + x_offset - 1;
3770     pt2.y = y - stdLineHeight;
3771     DrawLine (pt1, pt2);
3772   }
3773 
3774   
3775   while (col_num < start_col && header_vnp != NULL && data_vnp != NULL)
3776   {
3777     col_num++;
3778     header_vnp = header_vnp->next;
3779     data_vnp = data_vnp->next;
3780   }
3781   
3782   /* draw unfrozen columns */
3783   while (header_vnp != NULL && data_vnp != NULL && x_offset < row_length)
3784   {
3785     chars_to_paint = MIN (header_vnp->choice, (row_length - x_offset)/char_width);
3786     StringNCpy (buf, data_vnp->data.ptrvalue, chars_to_paint);
3787     buf [chars_to_paint] = 0;
3788     chars_to_paint = PrepareTableDisplayTextBuffer (buf, 
3789                                    (row_length - x_offset) / char_width,
3790                                    header_vnp->choice,
3791                                    data_vnp->data.ptrvalue);
3792 
3793     PaintStringEx ( (CharPtr)buf, x + x_offset, y);
3794     x_offset += (chars_to_paint + 2) * char_width;
3795     header_vnp = header_vnp->next;
3796     data_vnp = data_vnp->next;
3797   }
3798 }
3799 
3800 static void OnDrawTableDisplay (PaneL p)
3801 {
3802   TableDisplayPtr dlg;
3803   BaR             sb_vert, sb_horiz;
3804   Int4            start_row, start_col;
3805   RecT            r;
3806   Int4            x, y, row, row_length;
3807   CharPtr         row_buffer;
3808   ValNodePtr      row_vnp;
3809   PoinT           pt1, pt2;
3810   Boolean         left_in_red;
3811 
3812   dlg = (TableDisplayPtr) GetObjectExtra (p);
3813   if (dlg == NULL)
3814   {
3815     return;
3816   }
3817   
3818   sb_vert  = GetSlateVScrollBar ((SlatE) p);
3819   sb_horiz = GetSlateHScrollBar ((SlatE) p);
3820   
3821   start_row = GetBarValue (sb_vert) + dlg->frozen_header;
3822   start_col = GetBarValue (sb_horiz) + dlg->frozen_left;
3823 
3824   ObjectRect (p, &r);
3825   InsetRect (&r, dlg->table_inset, dlg->table_inset);
3826   x = r.left + 1;
3827   y = r.top + stdLineHeight;
3828 
3829   SelectFont (programFont); 
3830   
3831   row_length = r.right - r.left - 2;
3832   row_buffer = (CharPtr) MemNew (((row_length / dlg->char_width) + 1) * sizeof (Char));
3833   
3834   for (row = 0, row_vnp = dlg->row_list;
3835        row < dlg->frozen_header && y <= r.bottom - 2 * dlg->table_inset && row_vnp != NULL;
3836        row++, row_vnp = row_vnp->next)
3837   {
3838     DrawTableDisplayLine (x, y, dlg->row_list->data.ptrvalue, row_vnp->data.ptrvalue,
3839                           row_buffer, row_length, dlg->frozen_left, start_col, 
3840                           dlg->char_width, dlg->descent, FALSE);
3841     y += stdLineHeight;
3842   }
3843   
3844   while (row < start_row && row_vnp != NULL)
3845   {
3846     row++;
3847     row_vnp = row_vnp->next;
3848   }
3849   
3850   while (row_vnp != NULL && y <= r.bottom - 2 * dlg->table_inset)
3851   {
3852     left_in_red = FALSE;
3853     if (dlg->left_in_red != NULL)
3854     {
3855       left_in_red = (dlg->left_in_red) (row, dlg->row_list, dlg->left_in_red_data);
3856     }
3857     DrawTableDisplayLine (x, y, dlg->row_list->data.ptrvalue, row_vnp->data.ptrvalue,
3858                           row_buffer, row_length, dlg->frozen_left, start_col,
3859                           dlg->char_width, dlg->descent, left_in_red);
3860     row_vnp = row_vnp->next;
3861     y += stdLineHeight;
3862     row++;
3863   }
3864   
3865   /* draw line to separate header from remaining lines */
3866   if (dlg->frozen_header > 0)
3867   {
3868     Black ();
3869     pt1.x = x;
3870     pt1.y = r.top + stdLineHeight + dlg->descent;
3871     pt2.x = x + row_length;
3872     pt2.y = r.top + stdLineHeight + dlg->descent;
3873     DrawLine (pt1, pt2);
3874   }
3875   
3876 
3877 }
3878 
3879 static void OnVScrollTableDisplay (BaR sb, SlatE s, Int4 newval, Int4 oldval)
3880 {
3881   RecT   r;
3882   WindoW temport;
3883 
3884   temport = SavePort (s);
3885   Select (s);
3886   ObjectRect (s, &r);
3887   InvalRect (&r);  
3888   RestorePort (temport);
3889   Update ();
3890 }
3891 
3892 static void OnHScrollTableDisplay (BaR sb, SlatE s, Int4 newval, Int4 oldval)
3893 {
3894   RecT   r;
3895   WindoW temport;
3896 
3897   temport = SavePort (s);
3898   Select (s);
3899   ObjectRect (s, &r);
3900   InvalRect (&r);  
3901   RestorePort (temport);
3902   Update ();
3903 }
3904 
3905 static PoinT GetTableDisplayCell (TableDisplayPtr dlg, PoinT pt)
3906 {
3907   BaR sb_horiz;
3908   BaR sb_vert;
3909   Int4 start_row, start_col;
3910   RecT r;
3911   PoinT cell_coord;
3912   Int4  x, y;
3913   ValNodePtr header_vnp;
3914   Int4  col_width;
3915   
3916   cell_coord.x = 0;
3917   cell_coord.y = 0;
3918   
3919   if (dlg == NULL || dlg->row_list == NULL)
3920   {
3921     return cell_coord;
3922   }
3923   
3924   sb_vert  = GetSlateVScrollBar ((SlatE) dlg->panel);
3925   sb_horiz = GetSlateHScrollBar ((SlatE) dlg->panel);
3926   
3927   start_row = GetBarValue (sb_vert) + dlg->frozen_header;
3928   start_col = GetBarValue (sb_horiz) + dlg->frozen_left;
3929   
3930   ObjectRect (dlg->panel, &r);
3931   InsetRect (&r, dlg->table_inset, dlg->table_inset);
3932   x = pt.x - r.left;
3933   y = pt.y - r.top;
3934   
3935   cell_coord.y = y / stdLineHeight;
3936   
3937   if (cell_coord.y >= dlg->frozen_header)
3938   {
3939     cell_coord.y += GetBarValue (sb_vert);
3940   }
3941 
3942   header_vnp = dlg->row_list->data.ptrvalue;
3943   
3944   col_width = 0;
3945   while (header_vnp != NULL && col_width + (header_vnp->choice + 2) * dlg->char_width < x
3946          && cell_coord.x < dlg->frozen_left)
3947   {
3948     cell_coord.x++;
3949     col_width += (header_vnp->choice + 2) * dlg->char_width;
3950     header_vnp = header_vnp->next;
3951   }
3952   
3953   if (cell_coord.x >= dlg->frozen_left)
3954   {
3955     /* skip over unfrozen columns not currently displayed */
3956     while (header_vnp != NULL && cell_coord.x < start_col)
3957     {
3958       header_vnp = header_vnp->next;
3959       cell_coord.x++;
3960     }
3961   
3962     while (header_vnp != NULL && col_width + (header_vnp->choice + 2) * dlg->char_width < x)
3963     {
3964       cell_coord.x++;
3965       col_width += (header_vnp->choice + 2) * dlg->char_width;
3966       header_vnp = header_vnp->next;
3967     }
3968   }
3969   return cell_coord;
3970 }
3971 
3972 extern CharPtr GetRowListCellText (ValNodePtr row_list, Int4 row, Int4 column)
3973 {
3974   ValNodePtr row_vnp, col_vnp;
3975   Int4       row_num, col_num;
3976   
3977   if (row_list == NULL || row < 0 || column < 0)
3978   {
3979     return NULL;
3980   }
3981   
3982   for (row_vnp = row_list, row_num = 0;
3983        row_vnp != NULL && row_num < row;
3984        row_vnp = row_vnp->next, row_num++)
3985   {
3986   }
3987   if (row_num != row || row_vnp == NULL)
3988   {
3989     return NULL;
3990   }
3991   for (col_vnp = row_vnp->data.ptrvalue, col_num = 0;
3992        col_vnp != NULL && col_num < column;
3993        col_vnp = col_vnp->next, col_num++)
3994   {
3995   }
3996   if (col_num != column || col_vnp == NULL)
3997   {
3998     return NULL;
3999   }
4000   else
4001   {
4002     return StringSave (col_vnp->data.ptrvalue);
4003   }  
4004 }
4005 
4006 static CharPtr TableDisplayGetTextForCell (TableDisplayPtr dlg, PoinT pt)
4007 {
4008   if (dlg == NULL || dlg->row_list == NULL || pt.x < 0 || pt.y < 0)
4009   {
4010     return NULL;
4011   }
4012   
4013   return GetRowListCellText (dlg->row_list, pt.y, pt.x);
4014 }
4015 
4016 static void TableDisplayOnClick (PaneL p, PoinT pt)
4017 {
4018   TableDisplayPtr dlg;
4019   Boolean         dbl_click;
4020   PoinT           cell_coord;
4021   PoinT           header_coord;
4022   CharPtr         cell_text;
4023   CharPtr         header_text;
4024   
4025   dlg = (TableDisplayPtr) GetObjectExtra (p);
4026   if (dlg == NULL)
4027   {
4028     return;
4029   }
4030   
4031   dbl_click = dblClick;
4032   if (dbl_click && dlg->dbl_click != NULL)
4033   {
4034     cell_coord = GetTableDisplayCell (dlg, pt);
4035     cell_text = TableDisplayGetTextForCell (dlg, cell_coord);
4036     header_coord.x = cell_coord.x;
4037     header_coord.y = 0;
4038     header_text = TableDisplayGetTextForCell (dlg, header_coord);
4039     (dlg->dbl_click) (cell_coord, header_text, cell_text, dlg->dbl_click_data);
4040     MemFree (cell_text);
4041     MemFree (header_text);
4042   }
4043 }
4044 
4045 extern FonT GetTableDisplayDefaultFont (void)
4046 {
4047   FonT display_font = NULL;
4048   
4049 #ifdef WIN_MAC
4050   display_font = ParseFont ("Monaco, 9");
4051 #endif
4052 #ifdef WIN_MSWIN
4053   display_font = ParseFont ("Courier, 9");
4054 #endif
4055 #ifdef WIN_MOTIF
4056   display_font = ParseFont ("fixed, 12");
4057 #endif  
4058   return display_font;
4059 }
4060 
4061 extern DialoG TableDisplayDialog (GrouP parent, Int4 width, Int4 height,
4062                                   Int4 frozen_header, Int4 frozen_left,
4063                                   TableDisplayDblClick dbl_click,
4064                                   Pointer dbl_click_data,
4065                                   TableDisplayLeftInRed left_in_red,
4066                                   Pointer left_in_red_data)
4067 {
4068   TableDisplayPtr dlg;
4069   GrouP           p;
4070   
4071   dlg = (TableDisplayPtr) MemNew (sizeof (TableDisplayData));
4072   if (dlg == NULL)
4073   {
4074     return NULL;
4075   }
4076   p = HiddenGroup (parent, -1, 0, NULL);
4077   SetObjectExtra (p, dlg, CleanupTableDisplayDialog);
4078   
4079   dlg->dialog = (DialoG) p;
4080   dlg->todialog = RowsToTableDisplayDialog;
4081   dlg->fromdialog = TableDisplayDialogToRows;
4082   dlg->dialogmessage = NULL;
4083   dlg->testdialog = NULL;
4084   
4085   dlg->row_list = NULL;
4086   dlg->frozen_header = frozen_header;
4087   dlg->frozen_left = frozen_left;
4088   dlg->table_inset = 4;
4089   dlg->dbl_click = dbl_click;
4090   dlg->dbl_click_data = dbl_click_data;
4091   dlg->left_in_red = left_in_red;
4092   dlg->left_in_red_data = left_in_red_data;
4093   
4094   dlg->display_font = GetTableDisplayDefaultFont ();
4095 
4096   SelectFont (dlg->display_font);
4097   dlg->char_width  = CharWidth ('0');
4098   dlg->descent = Descent ();
4099   
4100   dlg->panel = AutonomousPanel4 (p, width, height, OnDrawTableDisplay,
4101                                OnVScrollTableDisplay, OnHScrollTableDisplay,
4102                                sizeof (TableDisplayData), NULL, NULL); 
4103   SetObjectExtra (dlg->panel, dlg, NULL);
4104   SetPanelClick(dlg->panel, TableDisplayOnClick, NULL, NULL, NULL);
4105   
4106   return (DialoG) p;  
4107 }
4108 
4109 typedef struct multiselectdialog
4110 {
4111   DIALOG_MESSAGE_BLOCK
4112   DoC                  doc;
4113   ValNodePtr           selected_list;
4114   ParData              listPar;
4115   ColData              listCol;
4116   Int4                 num_choices;
4117   Nlm_ChangeNotifyProc change_notify;
4118   Pointer              change_userdata;    
4119 } MultiSelectDialogData, PNTR MultiSelectDialogPtr;
4120 
4121 static void DataToMultiSelectionDialog (DialoG d, Pointer userdata)
4122 {
4123   MultiSelectDialogPtr dlg;
4124   ValNodePtr           vnp;
4125   Boolean              all_selected = FALSE;
4126   
4127   dlg = (MultiSelectDialogPtr) GetObjectExtra (d);
4128   if (dlg == NULL) return;
4129   
4130   dlg->selected_list = ValNodeFree (dlg->selected_list);
4131   for (vnp = (ValNodePtr) userdata; vnp != NULL && ! all_selected; vnp = vnp->next)
4132   {
4133     if (vnp->data.intvalue == 1)
4134     {
4135       all_selected = TRUE;
4136     }
4137     else
4138     {
4139       ValNodeAddInt (&(dlg->selected_list), vnp->data.intvalue, vnp->data.intvalue);
4140     }
4141   }
4142   if (all_selected)
4143   {
4144     dlg->selected_list = ValNodeFree (dlg->selected_list);
4145     ValNodeAddInt (&(dlg->selected_list), 1, 1);
4146   }
4147   InvalDocRows (dlg->doc, 0, 0, 0);
4148 }
4149 
4150 static Pointer MultiSelectionDialogToData (DialoG d)
4151 {
4152   MultiSelectDialogPtr dlg;
4153   ValNodePtr           output_list = NULL, vnp;
4154  
4155   dlg = (MultiSelectDialogPtr) GetObjectExtra (d);
4156   if (dlg == NULL) return NULL;
4157   
4158   for (vnp = dlg->selected_list; vnp != NULL; vnp = vnp->next)
4159   {
4160     ValNodeAddInt (&output_list, vnp->choice, vnp->data.intvalue);
4161   }
4162   return output_list;
4163 }
4164 
4165 static void 
4166 AddChoiceToSelection 
4167 (Int2                 choice_num,
4168  Boolean              remove_other_choices,
4169  MultiSelectDialogPtr dlg)
4170 {
4171   ValNodePtr already_sel, vnp;
4172   
4173   if (dlg == NULL || dlg->doc == NULL || choice_num < 1)
4174   {
4175     return;
4176   }
4177   
4178   if (choice_num == 1)
4179   {
4180     remove_other_choices = TRUE;
4181   }
4182   else 
4183   {
4184     /* if we have added a choice other than "All", remove the "All"
4185      * selection if it was present.
4186      */
4187     ValNodeFree (ValNodeExtractList (&(dlg->selected_list), 1));
4188     InvalDocRows (dlg->doc, 1, 1, 1);
4189   }
4190   
4191   already_sel = ValNodeExtractList (&(dlg->selected_list), choice_num);
4192   if (already_sel == NULL)
4193   {
4194     if (remove_other_choices)
4195     {
4196       /* delete old selections */
4197       for (vnp = dlg->selected_list; vnp != NULL; vnp = vnp->next)
4198       {
4199         InvalDocRows (dlg->doc, vnp->choice, 1, 1);
4200       }
4201       dlg->selected_list = ValNodeFree (dlg->selected_list);      
4202       ValNodeAddInt (&dlg->selected_list, choice_num, choice_num);
4203       InvalDocRows (dlg->doc, choice_num, 1, 1);
4204     }
4205     else
4206     {
4207       /* add new selection */
4208       ValNodeAddInt (&(dlg->selected_list), choice_num, choice_num);
4209       InvalDocRows (dlg->doc, choice_num, 1, 1);
4210     }
4211   }
4212   else
4213   {
4214     already_sel = ValNodeFree (already_sel);
4215     InvalDocRows (dlg->doc, choice_num, 1, 1); 
4216   }
4217   if (dlg->change_notify != NULL)
4218   {
4219     (dlg->change_notify) (dlg->change_userdata);
4220   }
4221 }
4222 
4223 static void SelectChoice (DoC d, PoinT pt)
4224 {
4225   Int2      item, row;
4226   Boolean   remove_other_choices;
4227   MultiSelectDialogPtr dlg;
4228   
4229   remove_other_choices = ! ctrlKey;
4230   
4231   dlg = (MultiSelectDialogPtr) GetObjectExtra (d);
4232   if (dlg == NULL) return;
4233   
4234   MapDocPoint (d, pt, &item, &row, NULL, NULL);
4235   AddChoiceToSelection (item, remove_other_choices, dlg);
4236 }
4237 
4238 static Boolean ChoiceHighlight (DoC doc, Int2 item, Int2 row, Int2 col)
4239 {
4240   MultiSelectDialogPtr dlg;
4241   ValNodePtr           vnp;
4242   
4243   dlg = (MultiSelectDialogPtr) GetObjectExtra (doc);
4244   if (dlg == NULL) return FALSE;
4245   
4246   for (vnp = dlg->selected_list; vnp != NULL; vnp = vnp->next)
4247   {
4248     if (vnp->data.intvalue == item)
4249     {
4250       return TRUE;
4251     }
4252   }
4253   return FALSE;
4254 }
4255 
4256 static void ChoiceOnKey (SlatE s, Char ch)
4257 {
4258   MultiSelectDialogPtr dlg;
4259   CharPtr              str;
4260   Int2                 start_pos;
4261   Boolean              found = FALSE;
4262   ValNodePtr           vnp;
4263   
4264   dlg = (MultiSelectDialogPtr) GetObjectExtra (s);
4265   if (dlg == NULL) return;
4266 
4267   if ( (int) ch == 0 ) return;
4268   
4269   if (isalpha (ch))
4270   {
4271     /* find the position of the last choice we added */
4272     for (vnp = dlg->selected_list; vnp != NULL && vnp->next != NULL; vnp = vnp->next)
4273     {}
4274     
4275     if (vnp == NULL)
4276     {
4277       GetOffset (dlg->doc, NULL, &start_pos);
4278       /* start pos is one less than document row */
4279       start_pos ++;
4280       /* want to start at row after top row */
4281       start_pos ++;
4282     }
4283     else
4284     {
4285       /* want to start at row after currently selected row */
4286       start_pos = vnp->choice + 1;
4287     }
4288     
4289     while (!found && start_pos <= dlg->num_choices)
4290     {
4291       str = GetDocText (dlg->doc, start_pos, 1, 1);
4292       if (tolower (str [0]) == tolower (ch))
4293       {
4294         SetOffset (dlg->doc, 0, start_pos - 1);
4295         AddChoiceToSelection (start_pos, TRUE, dlg);
4296         found = TRUE;
4297       }
4298       str = MemFree (str);
4299       start_pos ++;
4300     }
4301     if (!found)
4302     {
4303       /* start searching at the top of the list */
4304       start_pos = 1;
4305       while (!found && start_pos <= dlg->num_choices)
4306       {
4307         str = GetDocText (dlg->doc, start_pos, 1, 1);
4308         if (tolower (str [0]) == tolower (ch))
4309         {
4310           SetOffset (dlg->doc, 0, start_pos - 1);
4311           AddChoiceToSelection (start_pos, TRUE, dlg);
4312           found = TRUE;
4313         }
4314         str = MemFree (str);
4315         start_pos ++;
4316       }
4317     }
4318   }
4319   else if (ch == NLM_DOWN)
4320   {
4321     /* down key */
4322     if (dlg->selected_list == NULL)
4323     {
4324       GetOffset (dlg->doc, NULL, &start_pos);
4325       start_pos ++;
4326     }
4327     else
4328     {
4329       start_pos = dlg->selected_list->choice;
4330     }
4331     start_pos ++;
4332     
4333     if (start_pos <= dlg->num_choices)
4334     {
4335       SetOffset (dlg->doc, 0, start_pos - 1);
4336       AddChoiceToSelection (start_pos, TRUE, dlg); 
4337       InvalDocRows (dlg->doc, 0, 0, 0);
4338     }
4339   }
4340   else if (ch == NLM_UP)
4341   {
4342     /* up key */
4343     if (dlg->selected_list == NULL)
4344     {
4345       GetOffset (dlg->doc, NULL, &start_pos);
4346       start_pos ++;
4347     }
4348     else
4349     {
4350       start_pos = dlg->selected_list->choice;
4351     }
4352     start_pos --;
4353     if (start_pos > 0)
4354     {
4355       SetOffset (dlg->doc, 0, start_pos - 1);
4356       AddChoiceToSelection (start_pos, TRUE, dlg); 
4357       InvalDocRows (dlg->doc, 0, 0, 0);
4358     }
4359   }
4360 }
4361 
4362 static DialoG 
4363 MultiSelectDialog 
4364 (GrouP      parent,
4365  ValNodePtr choice_list,
4366  Int4       list_height,
4367  Nlm_ChangeNotifyProc     change_notify,
4368  Pointer                  change_userdata)
4369 {
4370   MultiSelectDialogPtr dlg;
4371   GrouP                p;
4372   Int4                 height;
4373   Int4                 width;
4374   RecT                 r;
4375   ValNodePtr           vnp;
4376   
4377   if (choice_list == NULL)
4378   {
4379     return NULL;
4380   }
4381   dlg = (MultiSelectDialogPtr) MemNew (sizeof (MultiSelectDialogData));
4382   if (dlg == NULL)
4383   {
4384     return NULL;
4385   }
4386   
4387   p = HiddenGroup (parent, -1, 0, NULL);
4388   SetObjectExtra (p, dlg, StdCleanupExtraProc);
4389   
4390   dlg->dialog = (DialoG) p;
4391   dlg->todialog = DataToMultiSelectionDialog;
4392   dlg->fromdialog = MultiSelectionDialogToData;
4393   dlg->dialogmessage = NULL;
4394   dlg->testdialog = NULL;  
4395   
4396   dlg->selected_list = NULL;
4397   dlg->change_notify = change_notify;
4398   dlg->change_userdata = change_userdata;
4399 
4400   
4401   SelectFont (systemFont);
4402   width = 0;
4403   for (vnp = choice_list; vnp != NULL; vnp = vnp->next)
4404   {
4405     width = MAX (width, StringWidth (vnp->data.ptrvalue) + 2);
4406   }
4407   
4408   dlg->num_choices = ValNodeLen (choice_list) + 1;
4409   
4410   height = LineHeight ();
4411   dlg->doc = DocumentPanel (p, width, height * list_height);
4412   SetObjectExtra (dlg->doc, dlg, NULL);
4413   
4414   dlg->listPar.openSpace = FALSE;
4415   dlg->listPar.keepWithNext = FALSE;
4416   dlg->listPar.keepTogether = FALSE;
4417   dlg->listPar.newPage = FALSE;
4418   dlg->listPar.tabStops = FALSE;
4419   dlg->listPar.minLines = 0;
4420   dlg->listPar.minHeight = 0;
4421 
4422   ObjectRect (dlg->doc, &r);
4423   InsetRect (&r, 4, 4);
4424   dlg->listCol.pixWidth = r.right - r.left;
4425   dlg->listCol.pixInset = 0;
4426   dlg->listCol.charWidth = 160;
4427   dlg->listCol.charInset = 0;
4428   dlg->listCol.font = systemFont;
4429   dlg->listCol.just = 'l';
4430   dlg->listCol.wrap = FALSE;
4431   dlg->listCol.bar = FALSE;
4432   dlg->listCol.underline = FALSE;
4433   dlg->listCol.left = FALSE;
4434   dlg->listCol.last = TRUE;  
4435   
4436     AppendText (dlg->doc, "All", &(dlg->listPar), &(dlg->listCol), programFont);
4437   for (vnp = choice_list; vnp != NULL; vnp = vnp->next)
4438   {
4439       AppendText (dlg->doc, vnp->data.ptrvalue, &(dlg->listPar), &(dlg->listCol), programFont);
4440   }
4441   SetDocAutoAdjust (dlg->doc, FALSE);
4442   SetDocProcs (dlg->doc, SelectChoice, NULL, NULL, NULL);
4443   SetDocShade (dlg->doc, NULL, NULL, ChoiceHighlight, NULL);
4444   SetSlateChar ((SlatE) dlg->doc, ChoiceOnKey);
4445   InvalDocument (dlg->doc);
4446 
4447   return (DialoG) p;
4448 }
4449 
4450 typedef struct selectiondialog
4451 {
4452   DIALOG_MESSAGE_BLOCK
4453   DialoG     multi_select_dlg;
4454   LisT       list_ctrl;
4455   PopuP      popup_ctrl;
4456   Int4       num_choices;
4457   CharPtr    err_msg;
4458   Nlm_ChangeNotifyProc     change_notify;
4459   Pointer                  change_userdata;
4460 } SelectionDialogData, PNTR SelectionDialogPtr;
4461 
4462 static void ResetSelectionDialog (SelectionDialogPtr dlg)
4463 {  
4464   if (dlg != NULL)
4465   {
4466     if (dlg->multi_select_dlg != NULL)
4467     {
4468       PointerToDialog (dlg->multi_select_dlg, NULL);
4469     }
4470     else if (dlg->list_ctrl != NULL)
4471     {
4472       SetValue (dlg->list_ctrl, 0);
4473     }
4474     else if (dlg->popup_ctrl != NULL)
4475     {
4476       SetValue (dlg->popup_ctrl, 0);
4477     }
4478   } 
4479 }
4480 
4481 static void SelectionDialogChanged (LisT l)
4482 {
4483   SelectionDialogPtr dlg;
4484 
4485   dlg = (SelectionDialogPtr) GetObjectExtra (l);
4486   if (dlg == NULL)
4487   {
4488     return;
4489   }
4490     
4491   if (dlg->change_notify != NULL)
4492   {
4493     (dlg->change_notify)(dlg->change_userdata);
4494   } 
4495 }
4496 
4497 static void SelectionDialogPopupChanged (PopuP p)
4498 {
4499   SelectionDialogPtr dlg;
4500  
4501   dlg = (SelectionDialogPtr) GetObjectExtra (p);
4502   if (dlg == NULL)
4503   {
4504     return;
4505   }
4506     
4507   if (dlg->change_notify != NULL)
4508   {
4509     (dlg->change_notify)(dlg->change_userdata);
4510   } 
4511 }
4512 
4513 static void SelectionListToSelectionDialog (DialoG d, Pointer userdata)
4514 {
4515   SelectionDialogPtr dlg;
4516   ValNodePtr         selected_list;
4517 
4518   dlg = (SelectionDialogPtr) GetObjectExtra (d);
4519   if (dlg == NULL)
4520   {
4521     return;
4522   }
4523   
4524   ResetSelectionDialog (dlg);  
4525   selected_list = (ValNodePtr) userdata;
4526   if (dlg->multi_select_dlg != NULL)
4527   {
4528     PointerToDialog (dlg->multi_select_dlg, selected_list);
4529   }
4530   else if (dlg->list_ctrl != NULL)
4531   {
4532     if (selected_list == NULL)
4533     {
4534       SetValue (dlg->list_ctrl, 0);
4535     }
4536     else
4537     {
4538       SetValue (dlg->list_ctrl, selected_list->data.intvalue);
4539     }
4540   }
4541   else if (dlg->popup_ctrl)
4542   {
4543     if (selected_list == NULL)
4544     {
4545       SetValue (dlg->popup_ctrl, 0);
4546     }
4547     else
4548     {
4549       SetValue (dlg->popup_ctrl, selected_list->data.intvalue);
4550     }
4551   }
4552 }
4553 
4554 
4555 static Pointer SelectionDialogToSelectionList (DialoG d)
4556 {
4557   SelectionDialogPtr dlg;
4558   ValNodePtr         sel_list = NULL, vnp;
4559   Int4               i = 0;
4560 
4561   dlg = (SelectionDialogPtr) GetObjectExtra (d);
4562   if (dlg == NULL)
4563   {
4564     return NULL;
4565   }
4566   
4567   if (dlg->multi_select_dlg != NULL)
4568   {
4569     sel_list = (ValNodePtr) DialogToPointer (dlg->multi_select_dlg);
4570     if (sel_list != NULL && sel_list->choice == 1)
4571     {
4572       sel_list = ValNodeFree (sel_list);
4573       for (i = 2; i <= dlg->num_choices; i++)
4574       {
4575         ValNodeAddInt (&sel_list, 0, i - 1);
4576       }
4577     }
4578     else
4579     {
4580       for (vnp = sel_list; vnp != NULL; vnp = vnp->next)
4581       {
4582         vnp->choice = 0;
4583         vnp->data.intvalue = vnp->data.intvalue - 1;
4584       }
4585     }
4586   }
4587   else
4588   {
4589     if (dlg->list_ctrl != NULL)
4590     {
4591       i = GetValue (dlg->list_ctrl);
4592     }
4593     else if (dlg->popup_ctrl != NULL)
4594     {
4595       i = GetValue (dlg->popup_ctrl);
4596     }
4597     if (i > 0)
4598     {
4599       ValNodeAddInt (&sel_list, 0, i);
4600     }
4601   }
4602   return (Pointer) sel_list;
4603 }
4604 
4605 static void SelectionDialogMessage (DialoG d, Int2 mssg)
4606 
4607 {
4608   SelectionDialogPtr dlg;
4609   ValNode            vn;
4610 
4611   dlg = (SelectionDialogPtr) GetObjectExtra (d);
4612   if (dlg != NULL) {
4613     switch (mssg) {
4614       case VIB_MSG_INIT :
4615         /* reset list */
4616         ResetSelectionDialog (dlg);
4617         break;
4618       case VIB_MSG_ENTER :
4619         if (dlg->multi_select_dlg != NULL)
4620         {
4621           Select (dlg->multi_select_dlg);
4622         }
4623         else if (dlg->list_ctrl != NULL)
4624         {
4625           Select (dlg->list_ctrl);
4626         }
4627         else if (dlg->popup_ctrl != NULL)
4628         {
4629           Select (dlg->popup_ctrl);
4630         }
4631         break;
4632       case NUM_VIB_MSG + 1:
4633         if (dlg->multi_select_dlg != NULL)
4634         {
4635           vn.next = NULL;
4636           vn.choice = 1;
4637           vn.data.intvalue = 1;
4638           PointerToDialog (dlg->multi_select_dlg, &vn);
4639         }
4640         else if (dlg->list_ctrl != NULL)
4641         {
4642           SetItemStatus (dlg->list_ctrl, 1, TRUE);
4643         }
4644         else if (dlg->popup_ctrl != NULL)
4645         {
4646           SetValue (dlg->popup_ctrl, 1);
4647         }
4648         SelectionDialogChanged (dlg->list_ctrl);
4649         break;
4650       default :
4651         break;
4652     }
4653   }
4654 }
4655 
4656 static ValNodePtr TestSelectionDialog (DialoG d)
4657 
4658 {
4659   SelectionDialogPtr dlg;
4660   ValNodePtr         head = NULL, vnp;
4661   Boolean            any_selected = FALSE;
4662 
4663   dlg = (SelectionDialogPtr) GetObjectExtra (d);
4664   if (dlg != NULL) {
4665     if (dlg->multi_select_dlg != NULL)
4666     {
4667       vnp = DialogToPointer (dlg->multi_select_dlg);
4668       if (vnp != NULL)
4669       {
4670         any_selected = TRUE;
4671         vnp = ValNodeFree (vnp);
4672       }
4673     }
4674     else if (dlg->list_ctrl != NULL)
4675     {
4676       if (GetValue (dlg->list_ctrl) > 0)
4677       {
4678         any_selected = TRUE;
4679       }
4680     }
4681     else if (dlg->popup_ctrl != NULL)
4682     {
4683       if (GetValue (dlg->popup_ctrl) > 0)
4684       {
4685         any_selected = TRUE;
4686       }
4687     }
4688     if (!any_selected)
4689     {
4690       head = AddStringToValNodeChain (head, dlg->err_msg, 1);
4691     }
4692   }
4693   return head;
4694 }
4695 
4696 /* err_msg is the message to put in the results from TestDialog if nothing is selected */
4697 /* choice_list should be a valnode list of strings to use for the names of the choices. */
4698 /* All is automatically included as a choice if allow_multi is true. */
4699 /* The ValNodeList returned is a list of integers indicating the position of the item
4700  * in the list - 1 is the first item, 2 is the second item, etc. */
4701 extern DialoG SelectionDialogExEx 
4702 (GrouP h,
4703  Nlm_ChangeNotifyProc     change_notify,
4704  Pointer                  change_userdata,
4705  Boolean                  allow_multi,
4706  CharPtr                  err_msg,
4707  ValNodePtr               choice_list,
4708  Int2                     list_height,
4709  Boolean                  force_list,
4710  Boolean                  force_popup)
4711 
4712 {
4713   SelectionDialogPtr  dlg;
4714   GrouP               p;
4715   ValNodePtr          vnp;
4716   Int4                num_choices;
4717   Int4                list_width = 8, item_width;
4718 
4719   if (choice_list == NULL)
4720   {
4721     return NULL;
4722   }
4723   
4724   dlg = (SelectionDialogPtr) MemNew (sizeof (SelectionDialogData));
4725   if (dlg == NULL)
4726   {
4727     return NULL;
4728   }
4729   
4730   p = HiddenGroup (h, 0, 2, NULL);
4731   SetObjectExtra (p, dlg, StdCleanupExtraProc);
4732 
4733   dlg->dialog = (DialoG) p;
4734   dlg->todialog = SelectionListToSelectionDialog;
4735   dlg->fromdialog = SelectionDialogToSelectionList;
4736   dlg->dialogmessage = SelectionDialogMessage;
4737   dlg->testdialog = TestSelectionDialog;
4738   dlg->change_notify = change_notify;
4739   dlg->change_userdata = change_userdata;
4740   dlg->err_msg = err_msg;
4741   
4742   num_choices = ValNodeLen (choice_list);
4743   
4744   if (allow_multi)
4745   {
4746     dlg->multi_select_dlg = MultiSelectDialog (p, choice_list, list_height,
4747                                                change_notify, change_userdata);
4748     dlg->num_choices = num_choices + 1;                                               
4749   }
4750   else
4751   {
4752     if (force_popup || (num_choices < 20 && ! force_list) || list_height == 1)
4753     {
4754       dlg->popup_ctrl = PopupList (p, TRUE, SelectionDialogPopupChanged);
4755       SetObjectExtra (dlg->popup_ctrl, dlg, NULL);
4756       for (vnp = choice_list; vnp != NULL; vnp = vnp->next) {
4757         PopupItem (dlg->popup_ctrl, vnp->data.ptrvalue);
4758       }
4759     }
4760     else
4761     {
4762       SelectFont (systemFont);
4763       for (vnp = choice_list; vnp != NULL; vnp = vnp->next) {
4764         item_width = StringWidth (vnp->data.ptrvalue);
4765         list_width = MAX (list_width, item_width);
4766       }
4767       /* add padding */
4768       list_width += StringWidth ("W");
4769       list_width = list_width / Nlm_stdCharWidth;
4770       dlg->list_ctrl = SingleList (p, list_width, list_height, SelectionDialogChanged);
4771       SetObjectExtra (dlg->list_ctrl, dlg, NULL);
4772       for (vnp = choice_list; vnp != NULL; vnp = vnp->next) {
4773         ListItem (dlg->list_ctrl, vnp->data.ptrvalue);
4774       }      
4775     }
4776     dlg->num_choices = num_choices;
4777   }
4778   
4779   return (DialoG) p;
4780 }
4781 
4782 
4783 extern DialoG SelectionDialogEx 
4784 (GrouP h,
4785  Nlm_ChangeNotifyProc     change_notify,
4786  Pointer                  change_userdata,
4787  Boolean                  allow_multi,
4788  CharPtr                  err_msg,
4789  ValNodePtr               choice_list,
4790  Int2                     list_height,
4791  Boolean                  force_list)
4792 
4793 {
4794   return SelectionDialogExEx (h, change_notify, change_userdata, allow_multi, err_msg, choice_list, list_height, force_list, FALSE);
4795 }
4796 
4797 
4798 extern DialoG SelectionDialog 
4799 (GrouP h,
4800  Nlm_ChangeNotifyProc     change_notify,
4801  Pointer                  change_userdata,
4802  Boolean                  allow_multi,
4803  CharPtr                  err_msg,
4804  ValNodePtr               choice_list,
4805  Int2                     list_height)
4806 {
4807   return SelectionDialogEx (h, change_notify, change_userdata, allow_multi,
4808                           err_msg, choice_list, list_height, FALSE);
4809 }
4810 
4811 typedef struct valnodeselection
4812 {
4813   DIALOG_MESSAGE_BLOCK
4814   DialoG           list_dlg;
4815   ValNodePtr       choice_list;
4816 
4817   Boolean             is_multi;  
4818   FreeValNodeProc     free_vn_proc;
4819   CopyValNodeDataProc copy_vn_proc;
4820   MatchValNodeProc    match_vn_proc;
4821   RemapValNodeProc    remap_vn_proc;
4822   
4823 } ValNodeSelectionData, PNTR ValNodeSelectionPtr;
4824 
4825 static void ValNodeSelectionListToDialog (DialoG d, Pointer userdata)
4826 {
4827   ValNodeSelectionPtr dlg;
4828   ValNodePtr          item_list, vnp_list, vnp_sel, pos_list = NULL;
4829   Int4                i;
4830   Boolean             found;
4831 
4832   dlg = (ValNodeSelectionPtr) GetObjectExtra (d);
4833   if (dlg == NULL)
4834   {
4835     return;
4836   }
4837   
4838   /* reset list control */
4839   PointerToDialog (dlg->list_dlg, NULL);  
4840   
4841   item_list = (ValNodePtr) userdata;
4842   for (vnp_list = item_list; vnp_list != NULL; vnp_list = vnp_list->next)
4843   {
4844     found = FALSE;
4845     i = 1;
4846     if (dlg->is_multi) {
4847       i++;
4848     }
4849     for (vnp_sel = dlg->choice_list;
4850          vnp_sel != NULL && !found;
4851          vnp_sel = vnp_sel->next, i++)
4852     {
4853       if ((dlg->match_vn_proc)(vnp_sel, vnp_list))
4854       {
4855         found = TRUE;
4856         ValNodeAddInt (&pos_list, 0, i);
4857       }
4858     }
4859   }
4860   PointerToDialog (dlg->list_dlg, pos_list);
4861   ValNodeFree (pos_list);  
4862 }
4863 
4864 static Pointer ValNodeSelectionDialogToList (DialoG d)
4865 {
4866   ValNodeSelectionPtr dlg;
4867   ValNodePtr          item_list = NULL, vnp_list, pos_list, vnp_pos;
4868   ValNodePtr          vnp_copy, vnp_last = NULL, vnp_test;
4869   Int4                i;
4870   Boolean             found;
4871 
4872   dlg = (ValNodeSelectionPtr) GetObjectExtra (d);
4873   if (dlg == NULL)
4874   {
4875     return NULL;
4876   }
4877   
4878   pos_list = DialogToPointer (dlg->list_dlg);
4879   for (vnp_pos = pos_list; vnp_pos != NULL; vnp_pos = vnp_pos->next)
4880   {
4881     for (i = 1, vnp_list = dlg->choice_list;
4882          i < vnp_pos->data.intvalue && vnp_list != NULL;
4883          i++, vnp_list = vnp_list->next)
4884     {
4885     }
4886     if (i == vnp_pos->data.intvalue && vnp_list != NULL)
4887     {
4888       /* make sure we don't already have this value in the list */
4889       for (vnp_test = item_list, found = FALSE;
4890            vnp_test != NULL && !found;
4891            vnp_test = vnp_test->next)
4892       {
4893         found = (dlg->match_vn_proc) (vnp_list, vnp_test);
4894       }
4895       
4896       if (found)
4897       {
4898         continue;
4899       }
4900       vnp_copy = (dlg->copy_vn_proc) (vnp_list);
4901       if (vnp_last == NULL)
4902       {
4903         item_list = vnp_copy;
4904       }
4905       else
4906       {
4907         vnp_last->next = vnp_copy;
4908       }
4909       vnp_last = vnp_copy;
4910     }
4911   }
4912   if (dlg->remap_vn_proc != NULL)
4913   {
4914     item_list = (dlg->remap_vn_proc) (item_list);
4915   }
4916   return item_list;  
4917 }
4918 
4919 static void CleanupValNodeSelectionDialogForm (GraphiC g, VoidPtr data)
4920 
4921 {
4922   ValNodeSelectionPtr dlg;
4923   ValNodePtr          vnp;
4924 
4925   dlg = (ValNodeSelectionPtr) data;
4926   if (dlg != NULL) {
4927     if (dlg->free_vn_proc != NULL)
4928     {
4929       for (vnp = dlg->choice_list; vnp != NULL; vnp = vnp->next)
4930       {
4931         (dlg->free_vn_proc) (vnp);
4932       }
4933     }
4934     dlg->choice_list = ValNodeFree (dlg->choice_list);
4935   }
4936   StdCleanupExtraProc (g, data);
4937 }
4938 
4939 static void ValNodeSelectionDialogMessage (DialoG d, Int2 mssg)
4940 
4941 {
4942   ValNodeSelectionPtr dlg;
4943 
4944   dlg = (ValNodeSelectionPtr) GetObjectExtra (d);
4945   if (dlg != NULL) {
4946     switch (mssg) {
4947       case VIB_MSG_INIT :
4948         /* reset list */
4949         PointerToDialog (dlg->list_dlg, NULL);
4950         break;
4951       case VIB_MSG_SELECT:
4952         Select (dlg->list_dlg);
4953         break;
4954       case VIB_MSG_ENTER :
4955         Select (dlg->list_dlg);
4956         break;
4957       case NUM_VIB_MSG + 1:
4958         SendMessageToDialog (dlg->list_dlg, NUM_VIB_MSG + 1);
4959         break;
4960       default :
4961         break;
4962     }
4963   }
4964 }
4965 
4966 static ValNodePtr TestValNodeSelectionDialog (DialoG d)
4967 
4968 {
4969   ValNodeSelectionPtr  dlg;
4970   ValNodePtr           head = NULL;
4971 
4972   dlg = (ValNodeSelectionPtr) GetObjectExtra (d);
4973   if (dlg != NULL) {
4974     head = TestDialog (dlg->list_dlg);
4975   }
4976   return head;
4977 }
4978 
4979 extern DialoG ValNodeSelectionDialogExEx
4980 (GrouP h,
4981  ValNodePtr               choice_list,
4982  Int2                     list_height,
4983  NameFromValNodeProc      name_proc,
4984  FreeValNodeProc          free_vn_proc,
4985  CopyValNodeDataProc      copy_vn_proc,
4986  MatchValNodeProc         match_vn_proc,
4987  CharPtr                  err_name,
4988  Nlm_ChangeNotifyProc     change_notify,
4989  Pointer                  change_userdata,
4990  Boolean                  allow_multi,
4991  Boolean                  force_list,
4992  Boolean                  force_popup,
4993  RemapValNodeProc         remap_vn_proc)
4994 {
4995   ValNodeSelectionPtr  dlg;
4996   GrouP                p;
4997   ValNodePtr           choice_name_list = NULL, vnp;
4998 
4999   if (choice_list == NULL || name_proc == NULL
5000       || copy_vn_proc == NULL || match_vn_proc == NULL)
5001   {
5002     return NULL;
5003   }
5004   
5005   dlg = (ValNodeSelectionPtr) MemNew (sizeof (ValNodeSelectionData));
5006   if (dlg == NULL)
5007   {
5008     return NULL;
5009   }
5010   
5011   p = HiddenGroup (h, 1, 0, NULL);
5012   SetObjectExtra (p, dlg, CleanupValNodeSelectionDialogForm);
5013   
5014   dlg->dialog = (DialoG) p;
5015   dlg->todialog = ValNodeSelectionListToDialog;
5016   dlg->fromdialog = ValNodeSelectionDialogToList;
5017   dlg->dialogmessage = ValNodeSelectionDialogMessage;
5018   dlg->testdialog = TestValNodeSelectionDialog;
5019   
5020   dlg->choice_list = choice_list;
5021   dlg->free_vn_proc = free_vn_proc;
5022   dlg->copy_vn_proc = copy_vn_proc;
5023   dlg->match_vn_proc = match_vn_proc;
5024   dlg->remap_vn_proc = remap_vn_proc;
5025 
5026   dlg->is_multi = allow_multi;
5027 
5028   for (vnp = choice_list; vnp != NULL; vnp = vnp->next)
5029   {
5030     ValNodeAddPointer (&choice_name_list, 0, (name_proc) (vnp));
5031   }
5032 
5033   dlg->list_dlg = SelectionDialogExEx (p, change_notify, change_userdata,
5034                                    allow_multi, err_name, choice_name_list, 
5035                                    list_height, force_list, force_popup);
5036   ValNodeFreeData (choice_name_list);  
5037   
5038   return (DialoG) p;
5039 }
5040 
5041 
5042 extern DialoG ValNodeSelectionDialogEx
5043 (GrouP h,
5044  ValNodePtr               choice_list,
5045  Int2                     list_height,
5046  NameFromValNodeProc      name_proc,
5047  FreeValNodeProc          free_vn_proc,
5048  CopyValNodeDataProc      copy_vn_proc,
5049  MatchValNodeProc         match_vn_proc,
5050  CharPtr                  err_name,
5051  Nlm_ChangeNotifyProc     change_notify,
5052  Pointer                  change_userdata,
5053  Boolean                  allow_multi,
5054  Boolean                  force_list,
5055  RemapValNodeProc         remap_vn_proc)
5056 {
5057   return ValNodeSelectionDialogExEx (h, choice_list, list_height, name_proc, free_vn_proc, copy_vn_proc,
5058                                      match_vn_proc, err_name, change_notify, change_userdata, allow_multi,
5059                                      force_list, FALSE, remap_vn_proc);
5060 }
5061 
5062 
5063 extern DialoG ValNodeSelectionDialog
5064 (GrouP h,
5065  ValNodePtr               choice_list,
5066  Int2                     list_height,
5067  NameFromValNodeProc      name_proc,
5068  FreeValNodeProc          free_vn_proc,
5069  CopyValNodeDataProc      copy_vn_proc,
5070  MatchValNodeProc         match_vn_proc,
5071  CharPtr                  err_name,
5072  Nlm_ChangeNotifyProc     change_notify,
5073  Pointer                  change_userdata,
5074  Boolean                  allow_multi)
5075 {
5076   return ValNodeSelectionDialogEx (h, choice_list, list_height,
5077                                    name_proc, free_vn_proc,
5078                                    copy_vn_proc, match_vn_proc, err_name,
5079                                    change_notify, change_userdata,
5080                                    allow_multi, FALSE, NULL);
5081 }
5082 
5083 extern DialoG EnumAssocSelectionDialog 
5084 (GrouP                 h,
5085  Nlm_EnumFieldAssocPtr eap,
5086  CharPtr               err_name,
5087  Boolean               allow_multi,
5088  Nlm_ChangeNotifyProc  change_notify,
5089  Pointer               change_userdata)
5090 
5091 {
5092   DialoG     dlg;
5093   ValNodePtr choice_list = NULL;
5094   
5095   if (eap == NULL)
5096   {
5097     return NULL;
5098   }
5099 
5100   while (eap->name != NULL)
5101   {
5102     if (!StringHasNoText (eap->name))
5103     {
5104       ValNodeAddPointer (&choice_list, eap->value, StringSave (eap->name));
5105     }
5106     eap++;
5107   }
5108   
5109   /* note - the ValNodeSelectionDialog will free the qual_choice_list when done */                                            
5110   dlg = ValNodeSelectionDialog (h, choice_list, TALL_SELECTION_LIST, ValNodeStringName,
5111                                 ValNodeSimpleDataFree, ValNodeStringCopy,
5112                                 ValNodeChoiceMatch, err_name, 
5113                                 change_notify, change_userdata, allow_multi);
5114 
5115   return dlg;
5116 }
5117 
5118 extern CharPtr ValNodeStringName (ValNodePtr vnp)
5119 {
5120   if (vnp == NULL || vnp->data.ptrvalue == NULL)
5121   {
5122     return NULL;
5123   }
5124   else
5125   {
5126     return StringSave (vnp->data.ptrvalue);
5127   }
5128 }
5129 
5130 extern void ValNodeSimpleDataFree (ValNodePtr vnp)
5131 {
5132   if (vnp != NULL && vnp->data.ptrvalue != NULL)
5133   {
5134     vnp->data.ptrvalue = MemFree (vnp->data.ptrvalue);
5135   }
5136 }
5137 
5138 extern ValNodePtr ValNodeStringCopy (ValNodePtr vnp)
5139 {
5140   ValNodePtr vnp_copy = NULL;
5141   if (vnp != NULL)
5142   {
5143     ValNodeAddPointer (&vnp_copy, vnp->choice, StringSave (vnp->data.ptrvalue));
5144   }
5145   return vnp_copy;
5146 }
5147 
5148 extern Boolean ValNodeChoiceMatch (ValNodePtr vnp1, ValNodePtr vnp2)
5149 {
5150   if (vnp1 == NULL || vnp2 == NULL)
5151   {
5152     return FALSE;
5153   }
5154   if (vnp1->choice == vnp2->choice)
5155   {
5156     return TRUE;
5157   }
5158   else
5159   {
5160     return FALSE;
5161   }
5162 }
5163 
5164 extern Boolean ValNodeStringMatch (ValNodePtr vnp1, ValNodePtr vnp2)
5165 {
5166   if (vnp1 == NULL || vnp2 == NULL)
5167   {
5168     return FALSE;
5169   }
5170   if (StringCmp (vnp1->data.ptrvalue, vnp2->data.ptrvalue) == 0)
5171   {
5172     return TRUE;
5173   }
5174   else
5175   {
5176     return FALSE;
5177   }
5178 }
5179 
5180 typedef struct sequenceselection
5181 {
5182   DIALOG_MESSAGE_BLOCK
5183   DialoG     sequence_list_dlg;
5184   ValNodePtr sequence_choice_list;
5185 } SequenceSelectionData, PNTR SequenceSelectionPtr;
5186 
5187 static void CleanupSequenceSelectionDialogForm (GraphiC g, VoidPtr data)
5188 
5189 {
5190   SequenceSelectionPtr dlg;
5191 
5192   dlg = (SequenceSelectionPtr) data;
5193   if (dlg != NULL) {
5194     dlg->sequence_choice_list = ValNodeFree (dlg->sequence_choice_list);
5195   }
5196   StdCleanupExtraProc (g, data);
5197 }
5198 
5199 static void ResetSequenceSelectionDialog (SequenceSelectionPtr dlg)
5200 {  
5201   if (dlg != NULL)
5202   {
5203     PointerToDialog (dlg->sequence_list_dlg, NULL);
5204   }
5205 }
5206 
5207 static void SequenceSelectionListToSequenceSelectionDialog (DialoG d, Pointer userdata)
5208 {
5209   SequenceSelectionPtr dlg;
5210   ValNodePtr           sequence_list, vnp_list, vnp_sel, pos_list = NULL;
5211   Int4                 i;
5212   SeqIdPtr             sip;
5213   Boolean              found;
5214 
5215   dlg = (SequenceSelectionPtr) GetObjectExtra (d);
5216   if (dlg == NULL)
5217   {
5218     return;
5219   }
5220   
5221   ResetSequenceSelectionDialog (dlg);  
5222   sequence_list = (ValNodePtr) userdata;
5223   for (vnp_list = sequence_list; vnp_list != NULL; vnp_list = vnp_list->next)
5224   {
5225     sip = (SeqIdPtr) vnp_list->data.ptrvalue;
5226     found = FALSE;
5227     while (sip != NULL && ! found)
5228     {
5229       for (vnp_sel = dlg->sequence_choice_list, i = 1;
5230            vnp_sel != NULL && !found;
5231            vnp_sel = vnp_sel->next, i++)
5232       {
5233         found = SeqIdIn (sip, vnp_sel->data.ptrvalue);
5234         if (found)
5235         {
5236           ValNodeAddInt (&pos_list, 0, i);
5237         }
5238       }
5239       sip = sip->next;
5240     }
5241   }
5242   PointerToDialog (dlg->sequence_list_dlg, pos_list);
5243   ValNodeFree (pos_list);
5244 }
5245 
5246 static Pointer SequenceSelectionDialogToSequenceSelectionList (DialoG d)
5247 {
5248   SequenceSelectionPtr dlg;
5249   ValNodePtr           sequence_list = NULL, vnp_list, pos_list, vnp_pos;
5250   Int4                 i;
5251 
5252   dlg = (SequenceSelectionPtr) GetObjectExtra (d);
5253   if (dlg == NULL)
5254   {
5255     return NULL;
5256   }
5257   
5258   pos_list = DialogToPointer (dlg->sequence_list_dlg);
5259   for (vnp_pos = pos_list; vnp_pos != NULL; vnp_pos = vnp_pos->next)
5260   {
5261     for (i = 1, vnp_list = dlg->sequence_choice_list;
5262          i < vnp_pos->data.intvalue && vnp_list != NULL;
5263          i++, vnp_list = vnp_list->next)
5264     {
5265     }
5266     if (i == vnp_pos->data.intvalue && vnp_list != NULL)
5267     {
5268       ValNodeAddPointer (&sequence_list, 0, vnp_list->data.ptrvalue);
5269     }
5270   }
5271   return sequence_list;
5272 }
5273 
5274 static void 
5275 GetSequenceChoiceList 
5276 (SeqEntryPtr sep,
5277  ValNodePtr PNTR list, 
5278  Boolean show_nucs, 
5279  Boolean show_prots)
5280 {
5281   BioseqPtr                bsp;
5282   BioseqSetPtr             bssp;
5283   
5284   if (sep == NULL) return;
5285   
5286   if (IS_Bioseq (sep))
5287   {
5288     bsp = (BioseqPtr) sep->data.ptrvalue;
5289     if (bsp == NULL) return;
5290     if (!show_nucs && ISA_na (bsp->mol))
5291     {
5292       return;
5293     }
5294     if (!show_prots && ISA_aa (bsp->mol))
5295     {
5296       return;
5297     }
5298     ValNodeAddPointer (list, 0, bsp->id);
5299   }
5300   else
5301   {
5302       bssp = (BioseqSetPtr) sep->data.ptrvalue;
5303     for (sep = bssp->seq_set; sep != NULL; sep = sep->next) 
5304     {
5305       GetSequenceChoiceList (sep, list, show_nucs, show_prots);
5306     }
5307   }
5308 }
5309 
5310 static void SequenceSelectionDialogMessage (DialoG d, Int2 mssg)
5311 
5312 {
5313   SequenceSelectionPtr dlg;
5314 
5315   dlg = (SequenceSelectionPtr) GetObjectExtra (d);
5316   if (dlg != NULL) {
5317     switch (mssg) {
5318       case VIB_MSG_INIT :
5319         /* reset list */
5320         ResetSequenceSelectionDialog (dlg);
5321         break;
5322       case VIB_MSG_SELECT:
5323         Select (dlg->sequence_list_dlg);
5324         break;
5325       case VIB_MSG_ENTER :
5326         Select (dlg->sequence_list_dlg);
5327         break;
5328       case NUM_VIB_MSG + 1:
5329         SendMessageToDialog (dlg->sequence_list_dlg, NUM_VIB_MSG + 1);
5330         break;
5331       default :
5332         break;
5333     }
5334   }
5335 }
5336 
5337 static ValNodePtr TestSequenceSelectionDialog (DialoG d)
5338 
5339 {
5340   SequenceSelectionPtr dlg;
5341   ValNodePtr           head = NULL;
5342 
5343   dlg = (SequenceSelectionPtr) GetObjectExtra (d);
5344   if (dlg != NULL) {
5345     head = TestDialog (dlg->sequence_list_dlg);
5346   }
5347   return head;
5348 }
5349 
5350 
5351 extern DialoG SequenceSelectionDialogEx 
5352 (GrouP h,
5353  Nlm_ChangeNotifyProc     change_notify,
5354  Pointer                  change_userdata,
5355  Boolean                  allow_multi,
5356  Boolean                  allow_none,
5357  Boolean                  show_nucs,
5358  Boolean                  show_prots,
5359  Uint2                    entityID,
5360  Int4                     list_height)
5361 
5362 {
5363   SequenceSelectionPtr  dlg;
5364   GrouP                 p;
5365   ValNodePtr                vnp;
5366   SeqEntryPtr               sep;
5367   SeqIdPtr                  sip;
5368   Char                      tmp[128];
5369   ValNodePtr            choice_name_list = NULL;
5370   
5371   if (!show_nucs && ! show_prots)
5372   {
5373     return NULL;
5374   }
5375   
5376   sep = GetTopSeqEntryForEntityID (entityID);
5377   if (sep == NULL)
5378   {
5379     return NULL;
5380   }
5381 
5382   dlg = (SequenceSelectionPtr) MemNew (sizeof (SequenceSelectionData));
5383   if (dlg == NULL)
5384   {
5385     return NULL;
5386   }
5387   
5388   p = HiddenGroup (h, 1, 0, NULL);
5389   SetObjectExtra (p, dlg, CleanupSequenceSelectionDialogForm);
5390 
5391   dlg->dialog = (DialoG) p;
5392   dlg->todialog = SequenceSelectionListToSequenceSelectionDialog;
5393   dlg->fromdialog = SequenceSelectionDialogToSequenceSelectionList;
5394   dlg->dialogmessage = SequenceSelectionDialogMessage;
5395   dlg->testdialog = TestSequenceSelectionDialog;
5396 
5397   if (allow_none) {
5398     dlg->sequence_choice_list = ValNodeNew (NULL);
5399     dlg->sequence_choice_list->choice = 0;
5400     dlg->sequence_choice_list->data.ptrvalue = NULL;
5401   } else {
5402     dlg->sequence_choice_list = NULL;
5403   }
5404   GetSequenceChoiceList (sep, &dlg->sequence_choice_list, show_nucs, show_prots);
5405   
5406   
5407   for (vnp = dlg->sequence_choice_list; vnp != NULL; vnp = vnp->next) {
5408     sip = SeqIdFindWorst ((SeqIdPtr) vnp->data.ptrvalue);
5409     if (sip == NULL) {
5410       sprintf (tmp, " ");
5411     } else {
5412       SeqIdWrite (sip, tmp, PRINTID_REPORT, sizeof (tmp));
5413     }
5414     ValNodeAddPointer (&choice_name_list, 0, StringSave (tmp));
5415   }
5416 
5417   dlg->sequence_list_dlg = SelectionDialog (p, change_notify, change_userdata,
5418                                             allow_multi, "sequence",
5419                                             choice_name_list, list_height);
5420   ValNodeFreeData (choice_name_list); 
5421   return (DialoG) p;
5422 }
5423 
5424 
5425 extern DialoG SequenceSelectionDialog 
5426 (GrouP h,
5427  Nlm_ChangeNotifyProc     change_notify,
5428  Pointer                  change_userdata,
5429  Boolean                  allow_multi,
5430  Boolean                  show_nucs,
5431  Boolean                  show_prots,
5432  Uint2                    entityID)
5433 {
5434   return SequenceSelectionDialogEx (h, change_notify, change_userdata, allow_multi, FALSE, show_nucs, show_prots, entityID, TALL_SELECTION_LIST);
5435 }
5436 
5437 
5438 extern DialoG SubSourceTypeDialog 
5439 (GrouP                    h,
5440  Int2                     list_height,
5441  Nlm_ChangeNotifyProc     change_notify,
5442  Pointer                  change_userdata,
5443  Boolean                  allow_multi,
5444  Boolean                  force_list,
5445  Boolean                  include_note)
5446 {
5447   ValNodePtr subsource_list = NULL;
5448   Int4       i;
5449 
5450   for (i = 0; current_subsource_subtype_alist[i].name != NULL; i++) {
5451     ValNodeAddPointer (&subsource_list, current_subsource_subtype_alist[i].value, StringSave (current_subsource_subtype_alist[i].name));
5452   }
5453   if (include_note) {
5454     ValNodeAddPointer (&subsource_list, SUBSRC_other, StringSave ("Note"));
5455   }
5456   
5457   return ValNodeSelectionDialogEx (h, subsource_list, list_height, 
5458                                    ValNodeStringName,
5459                                    ValNodeSimpleDataFree, 
5460                                    ValNodeStringCopy,
5461                                    ValNodeChoiceMatch, "subsource list", 
5462                                    change_notify, change_userdata, allow_multi, force_list, NULL);
5463 }
5464 
5465 
5466 extern DialoG OrgModTypeDialog 
5467 (GrouP                    h,
5468  Int2                     list_height,
5469  Nlm_ChangeNotifyProc     change_notify,
5470  Pointer                  change_userdata,
5471  Boolean                  allow_multi,
5472  Boolean                  force_list,
5473  Boolean                  include_note)
5474 {
5475   ValNodePtr orgmod_list = NULL;
5476   Int4       i;
5477 
5478   for (i = 0; current_orgmod_subtype_alist[i].name != NULL; i++) {
5479     ValNodeAddPointer (&orgmod_list, current_orgmod_subtype_alist[i].value, StringSave (current_orgmod_subtype_alist[i].name));
5480   }
5481   if (include_note) {
5482     ValNodeAddPointer (&orgmod_list, ORGMOD_other, StringSave ("Note"));
5483   }
5484   
5485   return ValNodeSelectionDialogEx (h, orgmod_list, list_height, 
5486                                    ValNodeStringName,
5487                                    ValNodeSimpleDataFree, 
5488                                    ValNodeStringCopy,
5489                                    ValNodeChoiceMatch, "orgmod list", 
5490                                    change_notify, change_userdata, allow_multi, force_list, NULL);
5491 }
5492 
5493 
5494 /*
5495 static CharPtr inferencePrefix [] = {
5496   "",
5497   "similar to sequence",
5498   "similar to AA sequence",
5499   "similar to DNA sequence",
5500   "similar to RNA sequence",
5501   "similar to RNA sequence, mRNA",
5502   "similar to RNA sequence, EST",
5503   "similar to RNA sequence, other RNA",
5504   "profile",
5505   "nucleotide motif",
5506   "protein motif",
5507   "ab initio prediction",
5508   NULL
5509 };
5510 
5511 ENUM_ALIST(inference_alist)
5512   { " ",                     0 },
5513   { "similar to sequence",   1 },
5514   { "similar to protein",    2 },
5515   { "similar to DNA",        3 },
5516   { "similar to RNA",        4 },
5517   { "similar to mRNA",       5 },
5518   { "similar to EST",        6 },
5519   { "similar to other RNA",  7 },
5520   { "profile",               8 },
5521   { "nucleotide motif",      9 },
5522   { "protein motif",        10 },
5523   { "ab initio prediction", 11 },
5524 END_ENUM_ALIST
5525 
5526 Uint2 inference_types [] = {
5527   TAGLIST_POPUP, TAGLIST_TEXT
5528 };
5529 
5530 Uint2 inference_widths [] = {
5531   0, 0
5532 };
5533 
5534 static EnumFieldAssocPtr inference_popups [] = {
5535   inference_alist, NULL
5536 };
5537 
5538 extern void GBQualsToInferenceDialog (DialoG d, SeqFeatPtr sfp)
5539 
5540 {
5541   Int2               best;
5542   Char               ch;
5543   GBQualPtr          gbq;
5544   ValNodePtr         head = NULL;
5545   Int2               j;
5546   ValNodePtr         last = NULL;
5547   size_t             len;
5548   CharPtr            rest;
5549   CharPtr            str;
5550   TagListPtr         tlp;
5551   Char               tmp [32];
5552   ValNodePtr         vnp;
5553 
5554   tlp = (TagListPtr) GetObjectExtra (d);
5555   if (tlp == NULL) return;
5556 
5557   if (sfp != NULL) {
5558     for (gbq = sfp->qual; gbq != NULL; gbq = gbq->next) {
5559       if (StringICmp (gbq->qual, "inference") != 0) continue;
5560       if (StringHasNoText (gbq->val)) continue;
5561       vnp = ValNodeNew (last);
5562       if (vnp == NULL) continue;
5563       if (head == NULL) {
5564         head = vnp;
5565       }
5566       last = vnp;
5567 
5568       rest = NULL;
5569       best = -1;
5570       for (j = 0; inferencePrefix [j] != NULL; j++) {
5571         len = StringLen (inferencePrefix [j]);
5572         if (StringNICmp (gbq->val, inferencePrefix [j], len) != 0) continue;
5573         rest = gbq->val + len;
5574         best = j;
5575       }
5576       if (best >= 0 && inferencePrefix [best] != NULL) {
5577         if (rest != NULL) {
5578           ch = *rest;
5579           while (IS_WHITESP (ch) || ch == ':') {
5580             rest++;
5581             ch = *rest;
5582           }
5583         }
5584         len = StringLen (rest);
5585         str = MemNew (len + 16);
5586         if (str != NULL) {
5587           sprintf (tmp, "%d", (int) best);
5588           StringCpy (str, tmp);
5589           StringCat (str, "\t");
5590           StringCat (str, rest);
5591           StringCat (str, "\n");
5592         }
5593         vnp->data.ptrvalue = str;
5594       } else {
5595         len + StringLen (gbq->val);
5596         str = MemNew (len + 8);
5597         if (str != NULL) {
5598           StringCpy (str, "0");
5599           StringCat (str, "\t");
5600           StringCat (str, gbq->val);
5601           StringCat (str, "\n");
5602         }
5603         vnp->data.ptrvalue = str;
5604       }
5605     }
5606   }
5607 
5608   SendMessageToDialog (tlp->dialog, VIB_MSG_RESET);
5609   tlp->vnp = head;
5610   SendMessageToDialog (tlp->dialog, VIB_MSG_REDRAW);
5611   for (j = 0, vnp = tlp->vnp; vnp != NULL; j++, vnp = vnp->next) continue;
5612   tlp->max = MAX ((Int2) 0, (Int2) (j - tlp->rows + 1));
5613   CorrectBarMax (tlp->bar, tlp->max);
5614   CorrectBarPage (tlp->bar, tlp->rows - 1, tlp->rows - 1);
5615 }
5616 
5617 static void VisStringDialogToGbquals (SeqFeatPtr sfp, DialoG d, CharPtr qual)
5618 
5619 {
5620   GBQualPtr   gbq, gbqlast = NULL;
5621   ValNodePtr  head = NULL, vnp;
5622   CharPtr     str;
5623 
5624   if (sfp == NULL || StringHasNoText (qual)) return;
5625   head = DialogToPointer (d);
5626   for (gbq = sfp->qual; gbq != NULL; gbq = gbq->next) {
5627     gbqlast = gbq;
5628   }
5629   for (vnp = head; vnp != NULL; vnp = vnp->next) {
5630     str = (CharPtr) vnp->data.ptrvalue;
5631     if (StringHasNoText (str)) continue;
5632     gbq = GBQualNew ();
5633     if (gbq == NULL) continue;
5634     gbq->qual = StringSave (qual);
5635     gbq->val = StringSave (str);
5636     if (gbqlast == NULL) {
5637       sfp->qual = gbq;
5638     } else {
5639       gbqlast->next = gbq;
5640     }
5641     gbqlast = gbq;
5642   }
5643   ValNodeFreeData (head);
5644 }
5645 
5646 extern void InferenceDialogToGBQuals (DialoG d, SeqFeatPtr sfp)
5647 
5648 {
5649   GBQualPtr   gbq;
5650   GBQualPtr   gbqlast = NULL;
5651   Int2        j;
5652   size_t      len;
5653   CharPtr     prefix;
5654   CharPtr     ptr;
5655   CharPtr     rest;
5656   CharPtr     str;
5657   TagListPtr  tlp;
5658   Int2        val;
5659   ValNodePtr  vnp;
5660 
5661   tlp = (TagListPtr) GetObjectExtra (d);
5662   if (tlp == NULL || sfp == NULL) return;
5663 
5664   for (gbq = sfp->qual; gbq != NULL; gbq = gbq->next) {
5665     gbqlast = gbq;
5666   }
5667 
5668   for (vnp = tlp->vnp; vnp != NULL; vnp = vnp->next) {
5669     if (StringHasNoText ((CharPtr) vnp->data.ptrvalue)) continue;
5670     ptr = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 0);
5671     TrimSpacesAroundString (ptr);
5672     prefix = NULL;
5673     if (StrToInt (ptr, &val)) {
5674       for (j = 0; inferencePrefix [j] != NULL; j++) {
5675         if (j == val) {
5676           prefix = inferencePrefix [j];
5677         }
5678       }
5679     }
5680     MemFree (ptr);
5681     rest = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 1);
5682     TrimSpacesAroundString (rest);
5683     if (StringDoesHaveText (prefix)) {
5684       len = StringLen (prefix) + StringLen (rest);
5685       str = (CharPtr) MemNew (len + 8);
5686       if (str != NULL) {
5687         if (StringDoesHaveText (prefix)) {
5688           StringCpy (str, prefix);
5689           if (StringDoesHaveText (rest)) {
5690             if (StringNICmp (rest, "(same species)", 14) != 0) {
5691               StringCat (str, ":");
5692             } else {
5693               StringCat (str, " ");
5694             }
5695           }
5696         }
5697         if (StringDoesHaveText (rest)) {
5698           StringCat (str, rest);
5699         }
5700         gbq = GBQualNew ();
5701         if (gbq != NULL) {
5702           gbq->qual = StringSave ("inference");
5703           gbq->val = str;
5704           if (gbqlast == NULL) {
5705             sfp->qual = gbq;
5706           } else {
5707             gbqlast->next = gbq;
5708           }
5709           gbqlast = gbq;
5710         }
5711       }
5712     }
5713     MemFree (rest);
5714   }
5715 }
5716 
5717 static DialoG CreateInferenceDialog (GrouP h, Uint2 rows, Int2 spacing, Int2 width)
5718 
5719 {
5720   inference_widths [1] = width;
5721   return CreateTagListDialog (h, rows, 2, spacing,
5722                               inference_types, inference_widths,
5723                               inference_popups, NULL, NULL);
5724 }
5725 */
5726 
5727 /* ************************ */
5728 
5729 /* inference dialog controls, utility functions */
5730 
5731 Uint2 accessionlist_types [] = {
5732   TAGLIST_POPUP, TAGLIST_TEXT
5733 };
5734 
5735 Uint2 accessionlist_widths [] = {
5736   0, 10
5737 };
5738 
5739 ENUM_ALIST(accn_type_alist)
5740   { " ",       0 },
5741   { "GenBank", 1 },
5742   { "EMBL",    2 },
5743   { "DDBJ",    3 },
5744   { "INSD",    4 },
5745   { "RefSeq",  5 },
5746   { "UniProt", 6 },
5747   { "Other",   7 },
5748 END_ENUM_ALIST
5749 
5750 static EnumFieldAssocPtr accessionlist_popups [] = {
5751   accn_type_alist, NULL
5752 };
5753 
5754 static CharPtr accnTypePrefix [] = {
5755   "",
5756   "GenBank",
5757   "EMBL",
5758   "DDBJ",
5759   "INSD",
5760   "RefSeq",
5761   "UniProt",
5762   "?",
5763   NULL
5764 };
5765 
5766 const Int4 numAccnTypePrefixes = sizeof (accnTypePrefix) / sizeof (CharPtr);
5767 
5768 static Int4 GetAccnTypeNum (CharPtr str)
5769 {
5770   Int4 i;
5771 
5772   if (StringHasNoText (str)) return 0;
5773 
5774   for (i = 1; i < numAccnTypePrefixes; i++)
5775   {
5776     if (StringCmp (accnTypePrefix[i], str) == 0)
5777     {
5778       return i;
5779     }
5780   }
5781   return 0;
5782 }
5783 
5784 
5785 static CharPtr ValForOneAccession (CharPtr str)
5786 {
5787   CharPtr cp, val_buf = NULL;
5788   CharPtr val_fmt = "%d\t%s";
5789   Int4    db;
5790 
5791   if (!StringHasNoText (str))
5792   {
5793     cp = StringChr (str, '|');
5794     if (cp == NULL)
5795     {
5796       if ((db = GetAccnTypeNum(str)) > 0)
5797       {
5798         val_buf = MemNew (sizeof (Char) * StringLen (val_fmt));
5799         sprintf (val_buf, val_fmt, db, " ");
5800       }
5801       else
5802       {
5803         val_buf = MemNew (sizeof (Char) * (StringLen (val_fmt) + StringLen (str)));
5804         sprintf (val_buf, val_fmt, 0, str);
5805       }
5806     }
5807     else
5808     {
5809       *cp = 0;
5810       db = GetAccnTypeNum (str);
5811       val_buf = MemNew (sizeof (Char) * (StringLen (val_fmt) + StringLen (cp + 1)));
5812       sprintf (val_buf, val_fmt, db, cp + 1);
5813       *cp = '|';
5814     }
5815   }
5816   return val_buf;
5817 }
5818 
5819 static void AccessionListDataToDialog (DialoG d, Pointer data)
5820 {
5821   TagListPtr    tlp;
5822   CharPtr       str, cp, val_buf;
5823   ValNodePtr    new_list = NULL, vnp;
5824   Int4          j;
5825   Int2          scroll_pos;
5826 
5827   tlp = (TagListPtr) GetObjectExtra (d);
5828   
5829   if (tlp == NULL) return;
5830   str = (CharPtr) data;
5831   
5832   cp = StringChr (str, ',');
5833   while (cp != NULL)
5834   {
5835     *cp = 0;
5836     val_buf = ValForOneAccession (str);
5837     if (val_buf != NULL)
5838     {
5839       ValNodeAddPointer (&new_list, 0, val_buf);
5840     }
5841     *cp = ',';
5842     str = cp + 1;
5843     cp = StringChr (str, ',');
5844   }
5845   val_buf = ValForOneAccession (str);
5846   if (val_buf != NULL)
5847   {
5848     ValNodeAddPointer (&new_list, 0, val_buf);
5849   }
5850 
5851   scroll_pos = 0;
5852   if (tlp->bar != NULL) 
5853   {
5854     scroll_pos = GetBarValue (tlp->bar);
5855   }
5856   else if (tlp->left_bar != NULL)
5857   {
5858     scroll_pos = GetBarValue (tlp->left_bar);
5859   }
5860 
5861   SendMessageToDialog (tlp->dialog, VIB_MSG_RESET);
5862   tlp->vnp = new_list;
5863   for (j = 0, vnp = tlp->vnp; vnp != NULL; j++, vnp = vnp->next) {
5864   }
5865   tlp->max = MAX ((Int2) 0, (Int2) (j - tlp->rows + 1));
5866   CorrectBarMax (tlp->bar, tlp->max);
5867   CorrectBarPage (tlp->bar, (Int2) (tlp->rows-1), (Int2) (tlp->rows-1));   
5868 
5869   /* retain scroll position */
5870   if (scroll_pos > tlp->max) {
5871     scroll_pos = tlp->max;
5872   }
5873   
5874   if (tlp->bar != NULL)
5875   {
5876     CorrectBarValue (tlp->bar, scroll_pos);      
5877   }
5878   if (tlp->left_bar != NULL)
5879   {
5880     CorrectBarValue (tlp->left_bar, scroll_pos);      
5881   }
5882     
5883   SendMessageToDialog (tlp->dialog, VIB_MSG_REDRAW);
5884   Update ();
5885  
5886 }
5887 
5888 
5889 static Pointer AccessionListDialogToData (DialoG d)
5890 {
5891   TagListPtr    tlp;
5892   ValNodePtr    vnp;
5893   Int4          result_len = 0, db;
5894   CharPtr       str, acc_str, result_str = NULL;
5895   Boolean       first_item = TRUE;
5896   
5897   tlp = (TagListPtr) GetObjectExtra (d);
5898   
5899   if (tlp == NULL) return NULL;
5900   
5901   for (vnp = tlp->vnp;
5902        vnp != NULL;
5903        vnp = vnp->next)
5904   {
5905     acc_str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 1);
5906     str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 0);
5907     if (!StringHasNoText (acc_str) || !StringHasNoText (str))
5908     {
5909       result_len += StringLen (acc_str);
5910       result_len += 1; /* comma */
5911       db = atoi (str);
5912       if (db >= 0 && db < numAccnTypePrefixes)
5913       {
5914         result_len += MAX (StringLen (accnTypePrefix[db]), 1);
5915       }
5916       else
5917       {
5918         result_len ++; /* will represent with ? */
5919       }
5920       result_len ++; /* for db/accession separator */
5921     }
5922     acc_str = MemFree (acc_str);
5923     str = MemFree (str);
5924   }
5925   
5926   if (result_len > 0) 
5927   {
5928     result_str = (CharPtr) MemNew (sizeof (Char) * (result_len + 1));
5929     for (vnp = tlp->vnp;
5930         vnp != NULL;
5931         vnp = vnp->next)
5932     {
5933       acc_str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 1);
5934       str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 0);
5935       db = (str == NULL ? 0 : atoi (str));
5936       str = MemFree (str);
5937       if (!StringHasNoText (acc_str) || db > 0)
5938       {
5939         if (first_item)
5940         {
5941           first_item = FALSE;
5942         }
5943         else
5944         {
5945           StringCat (result_str, ",");
5946         }
5947 
5948         if (db > 0 && db < numAccnTypePrefixes)
5949         {
5950           StringCat (result_str, accnTypePrefix[db]);
5951         }
5952         else
5953         {
5954           StringCat (result_str, "?");
5955         }
5956         StringCat (result_str, "|");
5957         if (!StringHasNoText (result_str)) {
5958           StringCat (result_str, acc_str);
5959         }
5960       }
5961       acc_str = MemFree (acc_str);
5962     }
5963     result_str[result_len] = 0;
5964   }
5965 
5966   return result_str;
5967 }
5968 
5969 
5970 static void RemoveEmptyAccessionStrings (CharPtr acc_list)
5971 {
5972   CharPtr cp_prev_end = NULL, cp_src, cp_dst;
5973 
5974   if (acc_list == NULL) return;
5975   
5976   cp_src = acc_list;
5977   cp_dst = acc_list;
5978   cp_prev_end = acc_list;
5979   while (*cp_src != 0)
5980   {
5981     if (*cp_src == '|' && (*(cp_src + 1) == ',' || *(cp_src + 1) == 0))
5982     {
5983       cp_dst = cp_prev_end;
5984       cp_prev_end = cp_dst;
5985       cp_src++;
5986     }
5987     else
5988     {
5989       *cp_dst = *cp_src;      
5990       if (*cp_src == ',')
5991       {
5992         cp_prev_end = cp_dst;
5993       }
5994       cp_dst++;
5995       cp_src++;
5996     }
5997   }
5998   *cp_dst = 0;
5999 }
6000 
6001 
6002 static CharPtr insdmessage =
6003 "GenBank, EMBL, and DDBJ records are part of the International Nucleotide " \
6004 "Sequence Database collaboration.\nThe database prefix for the /inference " \
6005 "qualifier in these cases is INSD by collaboration policy.";
6006 
6007 
6008 static Boolean ReplaceDatabaseStrings (CharPtr PNTR str)
6009 {
6010   Boolean changed_db = FALSE;
6011 
6012   if (str == NULL || *str == NULL) return FALSE;
6013 
6014   if (StringSearch (*str, "GenBank|") != NULL)
6015   {
6016     changed_db = TRUE;
6017     FindReplaceString (str, "GenBank|", "INSD|", TRUE, FALSE);
6018   }
6019   if (StringSearch (*str, "EMBL|") != NULL)
6020   {
6021     changed_db = TRUE;
6022     FindReplaceString (str, "EMBL|", "INSD|", TRUE, FALSE);
6023   }
6024   if (StringSearch (*str, "DDBJ|") != NULL)
6025   {
6026     changed_db = TRUE;
6027     FindReplaceString (str, "DDBJ|", "INSD|", TRUE, FALSE);
6028   }
6029 
6030   if (changed_db)
6031   {
6032     if (GetAppProperty ("InternalNcbiSequin") == NULL) {
6033       Message (MSG_OK, "%s", insdmessage);
6034     }
6035   }
6036 
6037   return changed_db;
6038 }
6039 
6040 
6041 static void ChangeInferAccessionList (Pointer data); 
6042 static TaglistCallback AccessionListCallbacks[] = 
6043 { ChangeInferAccessionList, ChangeInferAccessionList };
6044 
6045 typedef struct inferevid {
6046   CharPtr  prefix;     /* from inferencePrefix     */
6047   Boolean  species;    /* optional (same species)  */
6048   CharPtr  database;   /* INSD, RefSeq, etc.       */
6049   CharPtr  db_other;   /* other database           */
6050   CharPtr  accession;  /* accession.version        */
6051   CharPtr  program;    /* common analysis program  */
6052   CharPtr  pr_other;   /* other program            */
6053   CharPtr  version;    /* program version          */
6054   CharPtr  basis1;     /* profile or motif         */
6055   CharPtr  basis2;     /*  evidence_basis texts    */
6056   CharPtr  accession_list; /* accession list for alignment */
6057 } InferEvid, PNTR InferEvidPtr;
6058 
6059 typedef struct inferdialog {
6060   DIALOG_MESSAGE_BLOCK
6061 
6062   DoC           inferdoc;
6063   Int2          currItem;
6064 
6065   PopuP         prefix;
6066   ButtoN        species;
6067   PopuP         database;
6068   TexT          db_other;
6069   TexT          accession;
6070   PopuP         program;
6071   TexT          pr_other;
6072   TexT          version;
6073   TexT          basis1;
6074   TexT          basis2;
6075   PrompT        inf_free_program_prompt;
6076   PrompT        inf_free_version_prompt;
6077   PrompT        accession_list_program_prompt;
6078   PrompT        accession_list_version_prompt;
6079   PrompT        accession_list_prompt;
6080   DialoG        accession_list;
6081 
6082   GrouP         inf_accn_group;
6083   GrouP         other_db_group;
6084   GrouP         inf_prog_group;
6085   GrouP         other_pr_group;
6086   GrouP         inf_free_group;
6087 
6088   Int2          numInf;
6089   InferEvidPtr  evidence [128];
6090 
6091 } InferDialog, PNTR InferDialogPtr;
6092 
6093 static InferEvidPtr InferEvidNew (
6094   void
6095 )
6096 
6097 {
6098   InferEvidPtr  iep;
6099 
6100   iep = MemNew (sizeof (InferEvid));
6101   if (iep == NULL) return NULL;
6102 
6103   return iep;
6104 }
6105 
6106 static InferEvidPtr InferEvidFree (
6107   InferEvidPtr iep
6108 )
6109 
6110 {
6111   if (iep == NULL) return NULL;
6112 
6113   MemFree (iep->prefix);
6114   MemFree (iep->database);
6115   MemFree (iep->accession);
6116   MemFree (iep->program);
6117   MemFree (iep->version);
6118   MemFree (iep->basis1);
6119   MemFree (iep->basis2);
6120   MemFree (iep->accession_list);
6121 
6122   return MemFree (iep);
6123 }
6124 
6125 static InferEvidPtr GetInferEvid (
6126   InferDialogPtr idp,
6127   Int2 item
6128 )
6129 
6130 {
6131   InferEvidPtr  iep;
6132 
6133   if (idp == NULL || item < 0 || item > 127) return NULL;
6134   iep = idp->evidence [item];
6135   if (iep != NULL) return iep;
6136 
6137   iep = InferEvidNew ();
6138   if (iep != NULL) {
6139     /*
6140     iep->prefix = StringSave (" ");
6141     iep->database = StringSave (" ");
6142     iep->db_other = StringSave ("");
6143     iep->accession = StringSave ("");
6144     iep->program = StringSave (" ");
6145     iep->pr_other = StringSave ("");
6146     iep->version = StringSave ("");
6147     iep->basis1 = StringSave ("");
6148     iep->basis2 = StringSave ("");
6149     */
6150   }
6151   idp->evidence [item] = iep;
6152   return iep;
6153 }
6154 
6155 /* inference DoC object tables */
6156 
6157 #define NUM_INFERENCE_LINES 3
6158 
6159 static ParData  inferParFmt = { FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0 };
6160 
6161 static ColData  inferColFmt [] = {
6162   {0, 5, 25, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE}, /* class     */
6163   {0, 5, 25, 2, NULL, 'l', FALSE, TRUE,  FALSE, FALSE, TRUE}   /* specifics */
6164 };
6165 
6166 static CharPtr inferencePrefix [] = {
6167   "",
6168   "similar to sequence",
6169   "similar to AA sequence",
6170   "similar to DNA sequence",
6171   "similar to RNA sequence",
6172   "similar to RNA sequence, mRNA",
6173   "similar to RNA sequence, EST",
6174   "similar to RNA sequence, other RNA",
6175   "profile",
6176   "nucleotide motif",
6177   "protein motif",
6178   "ab initio prediction",
6179   "alignment",
6180   NULL
6181 };
6182 
6183 ENUM_ALIST(inference_alist)
6184   { " ",                     0 },
6185   { "similar to sequence",   1 },
6186   { "similar to protein",    2 },
6187   { "similar to DNA",        3 },
6188   { "similar to RNA",        4 },
6189   { "similar to mRNA",       5 },
6190   { "similar to EST",        6 },
6191   { "similar to other RNA",  7 },
6192   { "profile",               8 },
6193   { "nucleotide motif",      9 },
6194   { "protein motif",        10 },
6195   { "ab initio prediction", 11 },
6196   { "alignment",            12 },
6197 END_ENUM_ALIST
6198 
6199 static CharPtr programPrefix [] = {
6200   "",
6201   "tRNAscan",
6202   "Genscan",
6203   "?",
6204   NULL
6205 };
6206 
6207 ENUM_ALIST(program_alist)
6208   { " ",        0 },
6209   { "tRNAscan", 1 },
6210   { "Genscan",  2 },
6211   { "Other",    3 },
6212 END_ENUM_ALIST
6213 
6214 static CharPtr PrintInferTable (
6215   DoC d,
6216   Int2 item,
6217   Pointer data
6218 )
6219 
6220 {
6221   CharPtr         buf;
6222   InferDialogPtr  idp;
6223   InferEvidPtr    iep;
6224   size_t          len;
6225 
6226   idp = (InferDialogPtr) GetObjectExtra (d);
6227   if (idp == NULL || item < 1 || item > 127) return NULL;
6228   iep = GetInferEvid (idp, item);
6229   if (iep == NULL) return NULL;
6230 
6231   len = StringLen (iep->prefix) + StringLen (iep->database) + StringLen (iep->db_other) + StringLen (iep->accession) +
6232         StringLen (iep->program) + StringLen (iep->pr_other) + StringLen (iep->version) + StringLen (iep->basis1) +
6233         StringLen (iep->basis2) + StringLen (iep->accession_list) + 50;
6234   buf = MemNew (len);
6235   if (buf == NULL) return NULL;
6236 
6237   if (StringHasNoText (iep->prefix)) {
6238     StringCat (buf, " \t \n");
6239     return buf;
6240   }
6241 
6242   StringCat (buf, iep->prefix);
6243 
6244   StringCat (buf, "\t");
6245 
6246   if (StringNICmp (iep->prefix, "similar to ", 11) == 0) {
6247     if (StringDoesHaveText (iep->accession)) {
6248       if (StringCmp (iep->database, "Other") == 0) {
6249         if (StringDoesHaveText (iep->db_other)) {
6250           StringCat (buf, iep->db_other);
6251           StringCat (buf, ":");
6252         }
6253       } else if (StringDoesHaveText (iep->database)) {
6254         StringCat (buf, iep->database);
6255         StringCat (buf, ":");
6256       }
6257       StringCat (buf, iep->accession);
6258     }
6259   } else if (StringNICmp (iep->prefix, "ab initio ", 10) == 0) {
6260     if (StringCmp (iep->program, "Other") == 0) {
6261       if (StringDoesHaveText (iep->pr_other)) {
6262         StringCat (buf, iep->pr_other);
6263         if (StringDoesHaveText (iep->version)) {
6264           StringCat (buf, ":");
6265           StringCat (buf, iep->version);
6266         }
6267       }
6268     } else if (StringDoesHaveText (iep->program)) {
6269       StringCat (buf, iep->program);
6270       if (StringDoesHaveText (iep->version)) {
6271         StringCat (buf, ":");
6272         StringCat (buf, iep->version);
6273       }
6274     }
6275   } else if (StringDoesHaveText (iep->basis1)) {
6276     StringCat (buf, iep->basis1);
6277     if (StringDoesHaveText (iep->basis2)) {
6278       StringCat (buf, ":");
6279       StringCat (buf, iep->basis2);
6280       if (StringCmp (iep->prefix, "alignment") == 0 && 
6281           StringDoesHaveText (iep->accession_list)) {
6282         StringCat (buf, ":");
6283         StringCat (buf, iep->accession_list);
6284       }
6285     }
6286   } else {
6287     StringCat (buf, " ");
6288   }
6289 
6290   StringCat (buf, "\n");
6291   return buf;
6292 }
6293 
6294 static void ShowInferenceGroup (
6295   InferDialogPtr idp
6296 )
6297 
6298 {
6299   CharPtr  str;
6300   UIEnum   val;
6301 
6302   if (idp == NULL) return;
6303   if (GetEnumPopup (idp->prefix, inference_alist, &val)) {
6304     if (val >= 1 && val <= 7) {
6305       SafeHide (idp->inf_prog_group);
6306       SafeHide (idp->inf_free_group);
6307       SafeShow (idp->inf_accn_group);
6308       SafeShow (idp->species);
6309       str = GetEnumPopupByName (idp->database, accn_type_alist);
6310       if (StringCmp (str, "Other") == 0) {
6311         SafeShow (idp->other_db_group);
6312       } else {
6313         SafeHide (idp->other_db_group);
6314       }
6315       MemFree (str);
6316     } else if (val >= 8 && val <= 10) {
6317       SafeHide (idp->inf_accn_group);
6318       SafeHide (idp->species);
6319       SafeHide (idp->inf_prog_group);
6320       SafeShow (idp->inf_free_group);
6321       SafeHide (idp->accession_list);
6322       SafeShow (idp->inf_free_program_prompt);
6323       SafeShow (idp->inf_free_version_prompt);
6324       SafeHide (idp->accession_list_program_prompt);
6325       SafeHide (idp->accession_list_version_prompt);
6326       SafeHide (idp->accession_list_prompt);
6327     } else if (val == 11) {
6328       SafeHide (idp->inf_accn_group);
6329       SafeHide (idp->species);
6330       SafeHide (idp->inf_free_group);
6331       SafeShow (idp->inf_prog_group);
6332       str = GetEnumPopupByName (idp->program, program_alist);
6333       if (StringCmp (str, "Other") == 0) {
6334         SafeShow (idp->other_pr_group);
6335       } else {
6336         SafeHide (idp->other_pr_group);
6337       }
6338       MemFree (str);
6339     } else if (val == 12) {
6340       SafeHide (idp->inf_accn_group);
6341       SafeHide (idp->species);
6342       SafeHide (idp->inf_prog_group);
6343       SafeShow (idp->inf_free_group);
6344       SafeShow (idp->accession_list);
6345       SafeHide (idp->inf_free_program_prompt);
6346       SafeHide (idp->inf_free_version_prompt);
6347       SafeShow (idp->accession_list_program_prompt);
6348       SafeShow (idp->accession_list_version_prompt);
6349       SafeShow (idp->accession_list_prompt);
6350     } else {
6351       SafeHide (idp->inf_accn_group);
6352       SafeHide (idp->species);
6353       SafeHide (idp->inf_prog_group);
6354       SafeHide (idp->inf_free_group);
6355     }
6356   } else {
6357     SafeHide (idp->inf_accn_group);
6358     SafeHide (idp->species);
6359     SafeHide (idp->inf_prog_group);
6360     SafeHide (idp->inf_free_group);
6361   }
6362   Update ();
6363 }
6364 
6365 static void SafeSetEnumPopupByName (PopuP lst, EnumFieldAssocPtr al, CharPtr name)
6366 
6367 {
6368   if (StringDoesHaveText (name)) {
6369     SetEnumPopupByName (lst, al, name);
6370   } else {
6371     SetEnumPopupByName (lst, al, " ");
6372   }
6373 }
6374 
6375 static void ChangeInferTableSelect (
6376   DoC d,
6377   Int2 item,
6378   Int2 row,
6379   Int2 col,
6380   Boolean dblClck
6381 )
6382 
6383 {
6384   InferDialogPtr  idp;
6385   InferEvidPtr    iep;
6386   Int2            itemOld1, itemOld2;
6387 
6388   idp = (InferDialogPtr) GetObjectExtra (d);
6389   if (idp == NULL) return;
6390   if (item == 0 || row == 0 || col == 0) return;
6391 
6392   GetDocHighlight (d, &itemOld1, &itemOld2);
6393   SetDocHighlight (d, item, item);
6394   UpdateDocument (d, itemOld1, itemOld2);
6395   UpdateDocument (d, item, item);
6396   idp->currItem = item;
6397 
6398   iep = GetInferEvid (idp, item);
6399   if (iep != NULL) {
6400     ResetClip ();
6401     SafeSetEnumPopupByName (idp->prefix, inference_alist, iep->prefix);
6402 
6403     SafeSetStatus (idp->species, iep->species);
6404     SafeSetEnumPopupByName (idp->database, accn_type_alist, iep->database);
6405     SafeSetTitle (idp->db_other, iep->db_other);
6406     SafeSetTitle (idp->accession, iep->accession);
6407 
6408     SafeSetEnumPopupByName (idp->program, program_alist, iep->program);
6409     SafeSetTitle (idp->pr_other, iep->pr_other);
6410     SafeSetTitle (idp->version, iep->version);
6411 
6412     SafeSetTitle (idp->basis1, iep->basis1);
6413     SafeSetTitle (idp->basis2, iep->basis2);
6414 
6415     ReplaceDatabaseStrings (&(iep->accession_list));
6416     PointerToDialog (idp->accession_list, iep->accession_list);
6417 
6418     ShowInferenceGroup (idp);
6419   }
6420 
6421   Update ();
6422 }
6423 
6424 static void CheckExtendInferTable (
6425   InferDialogPtr idp
6426 )
6427 
6428 {
6429   Int2  numItems;
6430 
6431   if (idp == NULL) return;
6432 
6433   GetDocParams (idp->inferdoc, &numItems, NULL);
6434   if (idp->currItem == numItems) {
6435     AppendItem (idp->inferdoc, PrintInferTable, idp, FALSE, 1,
6436                 &inferParFmt, inferColFmt, systemFont);
6437   }
6438 
6439   Update ();
6440 }
6441 
6442 static void ChangeInferPrefix (
6443   PopuP p
6444 )
6445 
6446 {
6447   AlistDialogPtr  adp;
6448   InferDialogPtr  idp;
6449   InferEvidPtr    iep;
6450   CharPtr         str;
6451 
6452   adp = (AlistDialogPtr) GetObjectExtra (p);
6453   if (adp == NULL) return;
6454   idp = (InferDialogPtr) adp->userdata;
6455   if (idp == NULL) return;
6456   iep = GetInferEvid (idp, idp->currItem);
6457   if (iep == NULL) return;
6458 
6459   str = GetEnumPopupByName (idp->prefix, inference_alist);
6460   iep->prefix = MemFree (iep->prefix);
6461   iep->prefix = str; /* allocated by GetEnumPopupByName */
6462 
6463   ShowInferenceGroup (idp);
6464 
6465   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6466   Update ();
6467 
6468   CheckExtendInferTable (idp);
6469 }
6470 
6471 static void ChangeSameSpecies (
6472   ButtoN b
6473 )
6474 
6475 {
6476   InferDialogPtr  idp;
6477   InferEvidPtr    iep;
6478 
6479   idp = (InferDialogPtr) GetObjectExtra (b);
6480   if (idp == NULL) return;
6481   iep = GetInferEvid (idp, idp->currItem);
6482   if (iep == NULL) return;
6483 
6484   iep->species = (Boolean) (GetStatus (b));
6485 
6486   ShowInferenceGroup (idp);
6487 
6488   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6489   Update ();
6490 
6491   CheckExtendInferTable (idp);
6492 }
6493 
6494 static void ChangeInferDatabase (
6495   PopuP p
6496 )
6497 
6498 
6499 {
6500   AlistDialogPtr  adp;
6501   InferDialogPtr  idp;
6502   InferEvidPtr    iep;
6503   CharPtr         str;
6504 
6505   adp = (AlistDialogPtr) GetObjectExtra (p);
6506   if (adp == NULL) return;
6507   idp = (InferDialogPtr) adp->userdata;
6508   if (idp == NULL) return;
6509   iep = GetInferEvid (idp, idp->currItem);
6510   if (iep == NULL) return;
6511 
6512   str = GetEnumPopupByName (idp->database, accn_type_alist);
6513   if (StringCmp (str, "GenBank") == 0 ||
6514       StringCmp (str, "EMBL") == 0 ||
6515       StringCmp (str, "DDBJ") == 0) {
6516     if (GetAppProperty ("InternalNcbiSequin") == NULL) {
6517       Message (MSG_OK, "%s", insdmessage);
6518     }
6519     SetEnumPopupByName (idp->database, accn_type_alist, "INSD");
6520     str = MemFree (str);
6521     str = StringSave ("INSD");
6522   }
6523   iep->database = MemFree (iep->database);
6524   iep->database = str; /* allocated by GetEnumPopupByName */
6525 
6526   ShowInferenceGroup (idp);
6527 
6528   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6529   Update ();
6530 
6531   CheckExtendInferTable (idp);
6532 }
6533 
6534 static void ChangeInferDbOther (
6535   TexT t
6536 )
6537 
6538 {
6539   InferDialogPtr  idp;
6540   InferEvidPtr    iep;
6541 
6542   idp = (InferDialogPtr) GetObjectExtra (t);
6543   if (idp == NULL) return;
6544   iep = GetInferEvid (idp, idp->currItem);
6545   if (iep == NULL) return;
6546 
6547   iep->db_other = MemFree (iep->db_other);
6548   iep->db_other = SaveStringFromText (t);
6549 
6550   ShowInferenceGroup (idp);
6551 
6552   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6553   Update ();
6554 
6555   CheckExtendInferTable (idp);
6556 }
6557 
6558 static void ChangeInferAccession (
6559   TexT t
6560 )
6561 
6562 {
6563   InferDialogPtr  idp;
6564   InferEvidPtr    iep;
6565 
6566   idp = (InferDialogPtr) GetObjectExtra (t);
6567   if (idp == NULL) return;
6568   iep = GetInferEvid (idp, idp->currItem);
6569   if (iep == NULL) return;
6570 
6571   iep->accession = MemFree (iep->accession);
6572   iep->accession = SaveStringFromText (t);
6573 
6574   ShowInferenceGroup (idp);
6575 
6576   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6577   Update ();
6578 
6579   CheckExtendInferTable (idp);
6580 }
6581 
6582 static void ChangeInferProgram (
6583   PopuP p
6584 )
6585 
6586 
6587 {
6588   AlistDialogPtr  adp;
6589   InferDialogPtr  idp;
6590   InferEvidPtr    iep;
6591   CharPtr         str;
6592 
6593   adp = (AlistDialogPtr) GetObjectExtra (p);
6594   if (adp == NULL) return;
6595   idp = (InferDialogPtr) adp->userdata;
6596   if (idp == NULL) return;
6597   iep = GetInferEvid (idp, idp->currItem);
6598   if (iep == NULL) return;
6599 
6600   str = GetEnumPopupByName (idp->program, program_alist);
6601   iep->program = MemFree (iep->program);
6602   iep->program = str; /* allocated by GetEnumPopupByName */
6603 
6604   ShowInferenceGroup (idp);
6605 
6606   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6607   Update ();
6608 
6609   CheckExtendInferTable (idp);
6610 }
6611 
6612 static void ChangeInferPrOther (
6613   TexT t
6614 )
6615 
6616 {
6617   InferDialogPtr  idp;
6618   InferEvidPtr    iep;
6619 
6620   idp = (InferDialogPtr) GetObjectExtra (t);
6621   if (idp == NULL) return;
6622   iep = GetInferEvid (idp, idp->currItem);
6623   if (iep == NULL) return;
6624 
6625   iep->pr_other = MemFree (iep->pr_other);
6626   iep->pr_other = SaveStringFromText (t);
6627 
6628   ShowInferenceGroup (idp);
6629 
6630   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6631   Update ();
6632 
6633   CheckExtendInferTable (idp);
6634 }
6635 
6636 static void ChangeInferVersion (
6637   TexT t
6638 )
6639 
6640 {
6641   InferDialogPtr  idp;
6642   InferEvidPtr    iep;
6643 
6644   idp = (InferDialogPtr) GetObjectExtra (t);
6645   if (idp == NULL) return;
6646   iep = GetInferEvid (idp, idp->currItem);
6647   if (iep == NULL) return;
6648 
6649   iep->version = MemFree (iep->version);
6650   iep->version = SaveStringFromText (t);
6651 
6652   ShowInferenceGroup (idp);
6653 
6654   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6655   Update ();
6656 
6657   CheckExtendInferTable (idp);
6658 }
6659 
6660 static void ChangeInferBasis1 (
6661   TexT t
6662 )
6663 
6664 {
6665   InferDialogPtr  idp;
6666   InferEvidPtr    iep;
6667 
6668   idp = (InferDialogPtr) GetObjectExtra (t);
6669   if (idp == NULL) return;
6670   iep = GetInferEvid (idp, idp->currItem);
6671   if (iep == NULL) return;
6672 
6673   iep->basis1 = MemFree (iep->basis1);
6674   iep->basis1 = SaveStringFromText (t);
6675 
6676   ShowInferenceGroup (idp);
6677 
6678   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6679   Update ();
6680 
6681   CheckExtendInferTable (idp);
6682 }
6683 
6684 static void ChangeInferBasis2 (
6685   TexT t
6686 )
6687 
6688 {
6689   InferDialogPtr  idp;
6690   InferEvidPtr    iep;
6691 
6692   idp = (InferDialogPtr) GetObjectExtra (t);
6693   if (idp == NULL) return;
6694   iep = GetInferEvid (idp, idp->currItem);
6695   if (iep == NULL) return;
6696 
6697   iep->basis2 = MemFree (iep->basis2);
6698   iep->basis2 = SaveStringFromText (t);
6699 
6700   ShowInferenceGroup (idp);
6701 
6702   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6703   Update ();
6704 
6705   CheckExtendInferTable (idp);
6706 }
6707 
6708 
6709 static void ChangeInferAccessionList (Pointer data)
6710 {
6711   InferDialogPtr  idp;
6712   InferEvidPtr    iep;
6713 
6714   idp = (InferDialogPtr) data;
6715   if (idp == NULL) return;
6716   iep = GetInferEvid (idp, idp->currItem);
6717   if (iep == NULL) return;
6718 
6719   iep->accession_list = MemFree (iep->accession_list);
6720   iep->accession_list = DialogToPointer (idp->accession_list);
6721   
6722   if (ReplaceDatabaseStrings (&(iep->accession_list)))
6723   {
6724     PointerToDialog (idp->accession_list, iep->accession_list);
6725   }
6726 
6727   ShowInferenceGroup (idp);
6728 
6729   UpdateDocument (idp->inferdoc, idp->currItem, idp->currItem);
6730   Update ();
6731 
6732   CheckExtendInferTable (idp);
6733 }
6734 
6735 
6736 static Boolean StringInList (CharPtr str, CharPtr PNTR list)
6737 
6738 {
6739   Int2  i;
6740 
6741   if (str == NULL || list == NULL) return FALSE;
6742 
6743   for (i = 0; list [i] != NULL; i++) {
6744     if (StringICmp (str, list[i]) == 0) return TRUE;
6745   }
6746 
6747   return FALSE;
6748 }
6749 
6750 extern void GBQualsToInferenceDialog (DialoG d, SeqFeatPtr sfp)
6751 
6752 {
6753   Int2            best;
6754   Char            ch;
6755   GBQualPtr       gbq;
6756   Int2            i, j, k;
6757   InferDialogPtr  idp;
6758   InferEvidPtr    iep;
6759   size_t          len;
6760   CharPtr         rest;
6761   CharPtr         str;
6762   CharPtr         tmp, tmp2;
6763 
6764   idp = (InferDialogPtr) GetObjectExtra (d);
6765   if (idp == NULL) return;
6766 
6767   if (sfp == NULL || sfp->qual == NULL) {
6768     Reset (idp->inferdoc);
6769     SetValue (idp->prefix, 0);
6770     SetStatus (idp->species, FALSE);
6771     SetValue (idp->database, 0);
6772     SetTitle (idp->db_other, "");
6773     SetTitle (idp->accession, "");
6774     SetValue (idp->program, 0);
6775     SetTitle (idp->pr_other, "");
6776     SetTitle (idp->version, "");
6777     SetTitle (idp->basis1, "");
6778     SetTitle (idp->basis2, "");
6779     SafeHide (idp->inf_accn_group);
6780     SafeHide (idp->inf_prog_group);
6781     SafeHide (idp->inf_free_group);
6782     idp->numInf = 0;
6783     idp->currItem = 1;
6784     for (i = 0; i < NUM_INFERENCE_LINES; i++) {
6785       AppendItem (idp->inferdoc, PrintInferTable, idp, FALSE, 1,
6786                   &inferParFmt, inferColFmt, systemFont);
6787     }
6788     SetDocHighlight (idp->inferdoc, 1, 1);
6789     return;
6790   }
6791 
6792   idp->numInf = 0;
6793   idp->currItem = 1;
6794   Reset (idp->inferdoc);
6795 
6796   for (k = 0; k < 128; k++) {
6797     iep = idp->evidence [k];
6798     InferEvidFree (iep);
6799     idp->evidence [k] = NULL;
6800   }
6801 
6802   for (gbq = sfp->qual, k = 0; gbq != NULL; gbq = gbq->next) {
6803     if (StringICmp (gbq->qual, "inference") != 0) continue;
6804     if (StringHasNoText (gbq->val)) continue;
6805 
6806     rest = NULL;
6807     best = -1;
6808     for (j = 0; inferencePrefix [j] != NULL; j++) {
6809       len = StringLen (inferencePrefix [j]);
6810       if (StringNICmp (gbq->val, inferencePrefix [j], len) != 0) continue;
6811       rest = gbq->val + len;
6812       best = j;
6813     }
6814 
6815     k++;
6816     iep = GetInferEvid (idp, k);
6817     if (iep == NULL) continue;
6818 
6819     str = NULL;
6820     if (best > 0 && inferencePrefix [best] != NULL) {
6821       iep->prefix = MemFree (iep->prefix);
6822       iep->prefix = StringSave(GetEnumName ((UIEnum) best, inference_alist));
6823 
6824       if (rest != NULL) {
6825         ch = *rest;
6826         while (IS_WHITESP (ch)) {
6827           rest++;
6828           ch = *rest;
6829         }
6830         if (StringNICmp (rest, "(same species)", 14) == 0) {
6831           iep->species = TRUE;
6832           rest += 14;
6833         } else {
6834           iep->species = FALSE;
6835         }
6836         ch = *rest;
6837         while (IS_WHITESP (ch) || ch == ':') {
6838           rest++;
6839           ch = *rest;
6840         }
6841       }
6842       if (StringDoesHaveText (rest)) {
6843         str = StringSave (rest);
6844       }
6845       tmp = StringChr (str, ':');
6846       if (tmp != NULL) {
6847         *tmp = '\0';
6848         tmp++;
6849         TrimSpacesAroundString (str);
6850         TrimSpacesAroundString (tmp);
6851       } else {
6852         TrimSpacesAroundString (str);
6853       }
6854       if (StringNICmp (iep->prefix, "similar to ", 11) == 0) {
6855         if (StringInList (str, accnTypePrefix)) {
6856           iep->database = MemFree (iep->database);
6857           iep->database = StringSaveNoNull (str);
6858           iep->accession = MemFree (iep->accession);
6859           iep->accession = StringSaveNoNull (tmp);
6860         } else if (tmp != NULL) {
6861           iep->database = MemFree (iep->database);
6862           iep->database = StringSaveNoNull ("Other");
6863           iep->db_other = MemFree (iep->db_other);
6864           iep->db_other = StringSaveNoNull (str);
6865           iep->accession = MemFree (iep->accession);
6866           iep->accession = StringSaveNoNull (tmp);
6867         } else {
6868           iep->database = MemFree (iep->database);
6869           iep->database = StringSaveNoNull (" ");
6870           iep->db_other = MemFree (iep->db_other);
6871           iep->accession = MemFree (iep->accession);
6872           iep->accession = StringSaveNoNull (str);
6873         }
6874       } else if (StringNICmp (iep->prefix, "ab initio ", 10) == 0) {
6875         if (StringInList (str, programPrefix)) {
6876           iep->program = MemFree (iep->program);
6877           iep->program = StringSaveNoNull (str);
6878         } else {
6879           iep->program = MemFree (iep->program);
6880           iep->program = StringSaveNoNull ("Other");
6881           iep->pr_other = MemFree (iep->pr_other);
6882           iep->pr_other = StringSaveNoNull (str);
6883         }
6884         iep->version = MemFree (iep->version);
6885         iep->version = StringSaveNoNull (tmp);
6886       } else {
6887         iep->basis1 = MemFree (iep->basis1);
6888         iep->basis1 = StringSaveNoNull (str);
6889         tmp2 = NULL;
6890         if (StringCmp (iep->prefix, "alignment") == 0)
6891         {
6892           tmp2 = StringChr (tmp, ':');
6893           if (tmp2 != NULL) {
6894             *tmp2 = 0;
6895             tmp2++;
6896           }
6897         }
6898         iep->basis2 = MemFree (iep->basis2);
6899         iep->basis2 = StringSaveNoNull (tmp);
6900         iep->accession_list = MemFree (iep->accession_list);
6901         iep->accession_list = StringSaveNoNull (tmp2);
6902       }
6903 
6904     } else {
6905       iep->prefix = StringSave ("???");
6906       str = StringSave (gbq->val);
6907       tmp = StringChr (str, ':');
6908       if (tmp != NULL) {
6909         *tmp = '\0';
6910         tmp++;
6911         TrimSpacesAroundString (str);
6912         TrimSpacesAroundString (tmp);
6913       } else {
6914         TrimSpacesAroundString (str);
6915       }
6916       iep->basis1 = MemFree (iep->basis1);
6917       iep->basis1 = StringSaveNoNull (str);
6918       iep->basis2 = MemFree (iep->basis2);
6919       iep->basis2 = StringSaveNoNull (tmp);
6920     }
6921 
6922     MemFree (str);
6923 
6924     AppendItem (idp->inferdoc, PrintInferTable, idp, FALSE, 1,
6925                 &inferParFmt, inferColFmt, systemFont);
6926 
6927     (idp->numInf)++;
6928   }
6929 
6930   AppendItem (idp->inferdoc, PrintInferTable, idp, FALSE, 1,
6931               &inferParFmt, inferColFmt, systemFont);
6932   k++;
6933 
6934   while (k < NUM_INFERENCE_LINES) {
6935     AppendItem (idp->inferdoc, PrintInferTable, idp, FALSE, 1,
6936                 &inferParFmt, inferColFmt, systemFont);
6937     k++;
6938   }
6939 
6940   ShowInferenceGroup (idp);
6941 
6942   UpdateDocument (idp->inferdoc, 0, 0);
6943 
6944   ChangeInferTableSelect (idp->inferdoc, 1, 1, 1, FALSE);
6945 
6946   Update ();
6947 }
6948 
6949 extern void InferenceDialogToGBQuals (DialoG d, SeqFeatPtr sfp, Boolean convertBadToNote)
6950 
6951 {
6952   CharPtr         first = NULL, second = NULL, accession_list = NULL;
6953   GBQualPtr       gbq, lastgbq;
6954   InferDialogPtr  idp;
6955   InferEvidPtr    iep;
6956   Int2            k, numItems;
6957   size_t          len;
6958   CharPtr         prefix = NULL;
6959   CharPtr         speciesies = NULL;
6960   CharPtr         str;
6961   UIEnum          val;
6962 
6963   idp = (InferDialogPtr) GetObjectExtra (d);
6964   if (idp == NULL || sfp == NULL) return;
6965 
6966   lastgbq = NULL;
6967   for (gbq = sfp->qual; gbq != NULL; gbq = gbq->next) {
6968     lastgbq = gbq;
6969   }
6970 
6971   GetDocParams (idp->inferdoc, &numItems, NULL);
6972   for (k = 1; k <= numItems; k++) {
6973     iep = GetInferEvid (idp, k);
6974     if (iep == NULL) continue;
6975 
6976     if (StringHasNoText (iep->prefix)) continue;
6977     gbq = GBQualNew ();
6978     if (gbq == NULL) continue;
6979 
6980     gbq->qual = StringSave ("inference");
6981 
6982     if (WhereInEnumPopup (inference_alist, iep->prefix, &val)) {
6983       if (val > 0 && val <= 12) {
6984         prefix = inferencePrefix [(int) val];
6985       }
6986     }
6987     speciesies = NULL;
6988     if (StringNICmp (iep->prefix, "similar to ", 11) == 0) {
6989       if (iep->species) {
6990         speciesies = " (same species)";
6991       }
6992       if (StringDoesHaveText (iep->accession)) {
6993         if (StringCmp (iep->database, "Other") == 0) {
6994           if (StringDoesHaveText (iep->db_other)) {
6995             first = iep->db_other;
6996           }
6997         } else if (StringDoesHaveText (iep->database)) {
6998           first = iep->database;
6999         }
7000         second = iep->accession;
7001       }
7002     } else if (StringNICmp (iep->prefix, "ab initio ", 10) == 0) {
7003       if (StringCmp (iep->program, "Other") == 0) {
7004         if (StringDoesHaveText (iep->pr_other)) {
7005           first = iep->pr_other;
7006         }
7007       } else if (StringDoesHaveText (iep->program)) {
7008         first = iep->program;
7009       }
7010       second = iep->version;
7011     } else {
7012       if (StringDoesHaveText (iep->basis1)) {
7013         first = iep->basis1;
7014         second = iep->basis2;
7015         if (StringCmp (iep->prefix, "alignment") == 0) {
7016           accession_list = iep->accession_list;
7017           RemoveEmptyAccessionStrings (accession_list);
7018           ReplaceDatabaseStrings (&accession_list);
7019         }
7020       }
7021     }
7022 
7023     len = StringLen (prefix) + StringLen (speciesies) + StringLen (first) + StringLen (second) + StringLen (accession_list);
7024     str = MemNew (len + 6);
7025     if (str != NULL) {
7026       StringCpy (str, prefix);
7027       StringCat (str, speciesies);
7028       StringCat (str, ":");
7029       StringCat (str, first);
7030       StringCat (str, ":");
7031       StringCat (str, second);
7032       if (StringCmp (prefix, "alignment") == 0 && accession_list != NULL) {
7033         StringCat (str, ":");
7034         StringCat (str, accession_list);
7035       }
7036       gbq->val = StringSave (str);
7037       MemFree (str);
7038     } else {
7039       gbq->val = StringSave ("?");
7040     }
7041 
7042     /* do not allow saving of bad qualifier */
7043     if (convertBadToNote &&
7044         ValidateInferenceQualifier (gbq->val, FALSE) != VALID_INFERENCE) {
7045       if (StringNICmp (gbq->val, "similar to ", 11) == 0) {
7046         len = StringLen ("similar to ") + StringLen (first) + StringLen (second);
7047         str = MemNew (len + 5);
7048         if (str != NULL) {
7049           StringCpy (str, "similar to ");
7050           if (StringDoesHaveText (first)) {
7051             StringCat (str, first);
7052             if (StringDoesHaveText (second)) {
7053               StringCat (str, ":");
7054               StringCat (str, second);
7055             }
7056           } else if (StringDoesHaveText (second)) {
7057             StringCat (str, second);
7058           }
7059           gbq->val = MemFree (gbq->val);
7060           gbq->val = StringSave (str);
7061           MemFree (str);
7062         }
7063       }
7064       gbq->qual = MemFree (gbq->qual);
7065       gbq->qual = StringSave ("note");
7066     }
7067 
7068     if (sfp->qual == NULL) {
7069       sfp->qual = gbq;
7070     }
7071     if (lastgbq != NULL) {
7072       lastgbq->next = gbq;
7073     }
7074     lastgbq = gbq;
7075     accession_list = NULL;
7076   }
7077 }
7078 
7079 static void CleanupInferProc (GraphiC g, VoidPtr data)
7080 
7081 {
7082   InferDialogPtr  idp;
7083   InferEvidPtr    iep;
7084   Int2            k;
7085 
7086   idp = (InferDialogPtr) data;
7087   if (idp != NULL) {
7088     for (k = 0; k < 128; k++) {
7089       iep = idp->evidence [k];
7090       InferEvidFree (iep);
7091       idp->evidence [k] = NULL;
7092     }
7093   }
7094   StdCleanupExtraProc (g, data);
7095 }
7096 
7097 static DialoG NewCreateInferenceDialog (
7098   GrouP prnt
7099 )
7100 
7101 {
7102   GrouP           cts, tbl, g0, g1, g2, g3, g4, g5, p, prompt_grp;
7103   FonT            fnt;
7104   Int2            i, hgt, wid;
7105   InferDialogPtr  idp;
7106 
7107   idp = (InferDialogPtr) MemNew (sizeof (InferDialog));
7108   if (idp == NULL) return NULL;
7109 
7110   p = HiddenGroup (prnt, -1, 0, NULL);
7111   SetGroupSpacing (p, 10, 10);
7112 
7113   SetObjectExtra (p, idp, CleanupInferProc);
7114   idp->dialog = (DialoG) p;
7115   /*
7116   idp->todialog = GBQualToInferTable;
7117   idp->fromdialog = InferTableToGBQual;
7118   */
7119 
7120   SelectFont (systemFont);
7121   hgt = LineHeight ();
7122   inferColFmt [0].pixWidth = MaxAlistWidths (inference_alist) + 5;
7123   inferColFmt [1].pixWidth = 25 * StringWidth ("X") + 5;
7124   SelectFont (systemFont);
7125 
7126   wid = 0;
7127   for (i = 0; i < 2; i++) {
7128     wid += inferColFmt [i].pixWidth;
7129   }
7130 
7131   tbl = HiddenGroup (p, -1, 0, NULL);
7132   SetGroupSpacing (tbl, 10, 5);
7133   SetGroupMargins (tbl, 5, 5);
7134 
7135   g0 = HiddenGroup (tbl, 15, 0, NULL);
7136   SetGroupSpacing (g0, 0, 3);
7137 #ifdef WIN_MSWIN
7138   fnt = systemFont;
7139 #else
7140   fnt = programFont;
7141 #endif
7142   /*
7143   StaticPrompt (g0, "Category", inferColFmt [0].pixWidth, 0, fnt, 'c');
7144   StaticPrompt (g0, "Explanation", inferColFmt [1].pixWidth, 0, fnt, 'c');
7145   */
7146 
7147   idp->inferdoc = DocumentPanel (tbl, wid + 2, NUM_INFERENCE_LINES * hgt + 2);
7148   SetObjectExtra (idp->inferdoc, idp, NULL);
7149   SetDocCache (idp->inferdoc, NULL, NULL, NULL);
7150   SetDocNotify (idp->inferdoc, ChangeInferTableSelect);
7151   idp->numInf = 0;
7152 
7153   for (i = 0; i < NUM_INFERENCE_LINES; i++) {
7154     AppendItem (idp->inferdoc, PrintInferTable, idp, FALSE, 1,
7155                 &inferParFmt, inferColFmt, systemFont);
7156   }
7157 
7158   cts = HiddenGroup (p, -1, 0, NULL);
7159   SetGroupSpacing (cts, 10, 10);
7160   SetGroupMargins (cts, 5, 5);
7161 
7162   g1 = HiddenGroup (cts, -10, 0, NULL);
7163   SetGroupSpacing (g1, 5, 5);
7164 
7165   StaticPrompt (g1, "Category", 0, popupMenuHeight, programFont, 'l');
7166   idp->prefix = CreateEnumPopupDialog (g1, TRUE, ChangeInferPrefix, inference_alist, (UIEnum) 0, idp);
7167 
7168   idp->species = CheckBox (g1, "(same species)", ChangeSameSpecies);
7169   SetObjectExtra (idp->species, idp, NULL);
7170   Hide (idp->species);
7171 
7172   g2 = HiddenGroup (cts, 0, 0, NULL);
7173   SetGroupSpacing (g2, 5, 5);
7174 
7175   g3 = HiddenGroup (g2, -3, 0, NULL);
7176   SetGroupSpacing (g3, 5, 5);
7177 
7178   StaticPrompt (g3, "Database", 0, dialogTextHeight, programFont, 'l');
7179   idp->database = CreateEnumPopupDialog (g3, TRUE, ChangeInferDatabase, accn_type_alist, (UIEnum) 0, idp);
7180   idp->other_db_group = HiddenGroup (g3, -4, 0, NULL);
7181   StaticPrompt (idp->other_db_group, ":", 0, dialogTextHeight, programFont, 'l');
7182   idp->db_other = DialogText (idp->other_db_group, "", 8, ChangeInferDbOther);
7183   SetObjectExtra (idp->db_other, idp, NULL);
7184   Hide (idp->other_db_group);
7185 
7186   StaticPrompt (g3, "Accession", 0, dialogTextHeight, programFont, 'l');
7187   idp->accession = DialogText (g3, "", 10, ChangeInferAccession);
7188   SetObjectExtra (idp->accession, idp, NULL);
7189 
7190   idp->inf_accn_group = g3;
7191   Hide (idp->inf_accn_group);
7192 
7193   g4 = HiddenGroup (g2, -3, 0, NULL);
7194   SetGroupSpacing (g4, 5, 5);
7195 
7196   StaticPrompt (g4, "Program", 0, dialogTextHeight, programFont, 'l');
7197   idp->program = CreateEnumPopupDialog (g4, TRUE, ChangeInferProgram, program_alist, (UIEnum) 0, idp);
7198   idp->other_pr_group = HiddenGroup (g4, -4, 0, NULL);
7199   StaticPrompt (idp->other_pr_group, ":", 0, dialogTextHeight, programFont, 'l');
7200   idp->pr_other = DialogText (idp->other_pr_group, "", 8, ChangeInferPrOther);
7201   SetObjectExtra (idp->pr_other, idp, NULL);
7202   Hide (idp->other_pr_group);
7203 
7204   StaticPrompt (g4, "Program Version", 0, dialogTextHeight, programFont, 'l');
7205   idp->version = DialogText (g4, "", 3, ChangeInferVersion);
7206   SetObjectExtra (idp->version, idp, NULL);
7207 
7208   idp->inf_prog_group = g4;
7209   Hide (idp->inf_prog_group);
7210 
7211   g5 = HiddenGroup (g2, 2, 0, NULL);
7212   SetGroupSpacing (g5, 5, 5);
7213 
7214   prompt_grp = HiddenGroup (g5, 0, 0, NULL);
7215   idp->inf_free_program_prompt = StaticPrompt (prompt_grp, "Program or Database", 0, dialogTextHeight, programFont, 'l');
7216   idp->accession_list_program_prompt = StaticPrompt (prompt_grp, "Program", 0, dialogTextHeight, programFont, 'l');
7217   idp->basis1 = DialogText (g5, "", 10, ChangeInferBasis1);
7218   SetObjectExtra (idp->basis1, idp, NULL);
7219 
7220   prompt_grp = HiddenGroup (g5, 0, 0, NULL);
7221   idp->inf_free_version_prompt = StaticPrompt (prompt_grp, "Version or Accession", 0, dialogTextHeight, programFont, 'l');
7222   idp->accession_list_version_prompt = StaticPrompt (prompt_grp, "Version", 0, dialogTextHeight, programFont, 'l');
7223 
7224   idp->basis2 = DialogText (g5, "", 10, ChangeInferBasis2);
7225   SetObjectExtra (idp->basis2, idp, NULL);
7226 
7227   idp->accession_list_prompt = StaticPrompt (g5, "Accessions", 0, dialogTextHeight, programFont, 'l');
7228   idp->accession_list = CreateTagListDialogEx3 (g5, 3, 2, 2,
7229                               accessionlist_types, accessionlist_widths,
7230                               accessionlist_popups, TRUE, FALSE, AccessionListDataToDialog, AccessionListDialogToData,
7231                               AccessionListCallbacks, idp,
7232                               FALSE, FALSE);
7233 
7234   idp->inf_free_group = g5;
7235   Hide (idp->inf_free_group);
7236 
7237   AlignObjects (ALIGN_CENTER, (HANDLE) tbl, (HANDLE) cts, NULL);
7238 
7239   idp->numInf = 0;
7240   idp->currItem = 1;
7241   SetDocHighlight (idp->inferdoc, 1, 1);
7242 
7243   return (DialoG) p;
7244 }
7245 
7246 
7247 /* ExistingText handling dialog and structures */
7248 typedef struct existingtextdlg 
7249 {
7250   GrouP pre_app_grp;
7251   GrouP delim_grp;
7252 } ExistingTextDlgData, PNTR ExistingTextDlgPtr;
7253 
7254 static void ChangePreAppIgnoreChoice (GrouP g)
7255 {
7256   ExistingTextDlgPtr etdp;
7257   Int4               handle_choice;
7258   
7259   etdp = (ExistingTextDlgPtr) GetObjectExtra (g);
7260   if (etdp == NULL)
7261   {
7262     return;
7263   }
7264   
7265   handle_choice = GetValue (etdp->pre_app_grp);
7266   if (handle_choice == 1 || handle_choice == 2)
7267   {
7268     Enable (etdp->delim_grp);
7269   }
7270   else
7271   {
7272     Disable (etdp->delim_grp);
7273   }
7274 }
7275 
7276 extern ExistingTextPtr GetExistingTextHandlerInfo (Int4 num_found, Boolean non_text)
7277 {
7278   WindoW                w;
7279   GrouP                 h, c;
7280   ExistingTextDlgData   etdd;
7281   ButtoN                b;
7282   ModalAcceptCancelData acd;
7283   ExistingTextPtr       etp;
7284   Char                  txt [128];
7285   MsgAnswer             ans;
7286   PrompT                ppt;
7287   Int4                  handle_choice;
7288 
7289   if (num_found <= 0)
7290   {
7291     return NULL;
7292   }
7293   
7294   sprintf (txt, "%d affected fields already contain a value.  Do you wish to overwrite existing text?",
7295            num_found);
7296   ans = Message (MSG_YNC, txt, 0, dialogTextHeight, systemFont, 'l');
7297   if (ans == ANS_CANCEL)
7298   {
7299     etp = (ExistingTextPtr) MemNew (sizeof (ExistingTextData));
7300     etp->existing_text_choice = eExistingTextChoiceCancel;
7301     return etp;
7302   }
7303   else if (ans == ANS_YES)
7304   {
7305     etp = (ExistingTextPtr) MemNew (sizeof (ExistingTextData));
7306     etp->existing_text_choice = eExistingTextChoiceReplaceOld;
7307     return etp;
7308   }
7309     
7310   w = MovableModalWindow(-20, -13, -10, -10, "How to Add New Text", NULL);
7311   h = HiddenGroup (w, -1, 0, NULL);
7312   SetGroupSpacing (h, 10, 10);
7313   etdd.pre_app_grp = HiddenGroup (h, 0, 3, ChangePreAppIgnoreChoice);
7314   SetGroupSpacing (etdd.pre_app_grp, 10, 10);
7315   RadioButton (etdd.pre_app_grp, "Append");
7316   RadioButton (etdd.pre_app_grp, "Prefix");
7317   RadioButton (etdd.pre_app_grp, "Ignore new text");
7318   SetValue (etdd.pre_app_grp, 1);
7319   SetObjectExtra (etdd.pre_app_grp, &etdd, NULL);
7320   
7321   ppt = StaticPrompt (h, "Separate new text and old text with", 
7322                       0, dialogTextHeight, programFont, 'c');
7323   etdd.delim_grp = HiddenGroup (h, 0, 4, NULL);
7324   SetGroupSpacing (etdd.delim_grp, 10, 10);
7325   RadioButton (etdd.delim_grp, "Semicolon");
7326   RadioButton (etdd.delim_grp, "Space");
7327   RadioButton (etdd.delim_grp, "Colon");
7328   RadioButton (etdd.delim_grp, "Do not separate");
7329   SetValue (etdd.delim_grp, 1);
7330   
7331   c = HiddenGroup (h, 2, 0, NULL);
7332   SetGroupSpacing (c, 10, 10);
7333   b = PushButton (c, "Accept", ModalAcceptButton);
7334   SetObjectExtra (b, &acd, NULL);
7335   b = PushButton (c, "Cancel", ModalCancelButton);
7336   SetObjectExtra (b, &acd, NULL);
7337   AlignObjects (ALIGN_CENTER, (HANDLE) etdd.pre_app_grp,
7338                               (HANDLE) ppt, 
7339                               (HANDLE) etdd.delim_grp, 
7340                               (HANDLE) c, 
7341                               NULL);
7342   Show (w);
7343   Select (w);
7344   acd.accepted = FALSE;
7345   acd.cancelled = FALSE;
7346   while (!acd.accepted && ! acd.cancelled)
7347   {
7348     ProcessExternalEvent ();
7349     Update ();
7350   }
7351   ProcessAnEvent ();
7352   etp = (ExistingTextPtr) MemNew (sizeof (ExistingTextData));
7353   if (acd.cancelled)
7354   {
7355     etp->existing_text_choice = eExistingTextChoiceCancel;
7356   }
7357   else
7358   {
7359     handle_choice = GetValue (etdd.pre_app_grp);
7360     if (handle_choice == 1)
7361     {
7362       switch (GetValue (etdd.delim_grp))
7363       {
7364         case 1:
7365           etp->existing_text_choice = eExistingTextChoiceAppendSemi;
7366           break;
7367         case 2:
7368           etp->existing_text_choice = eExistingTextChoiceAppendSpace;
7369           break;
7370         case 3:
7371           etp->existing_text_choice = eExistingTextChoiceAppendColon;
7372           break;
7373         case 4:
7374           etp->existing_text_choice = eExistingTextChoiceAppendNone;
7375           break;
7376       }
7377     }
7378     else if (handle_choice == 2)
7379     {
7380       switch (GetValue (etdd.delim_grp))
7381       {
7382         case 1:
7383           etp->existing_text_choice = eExistingTextChoicePrefixSemi;
7384           break;
7385         case 2:
7386           etp->existing_text_choice = eExistingTextChoicePrefixSpace;
7387           break;
7388         case 3:
7389           etp->existing_text_choice = eExistingTextChoicePrefixColon;
7390           break;
7391         case 4:
7392           etp->existing_text_choice = eExistingTextChoicePrefixNone;
7393           break;
7394       }
7395     }
7396     else
7397     {
7398       etp->existing_text_choice = eExistingTextChoiceLeaveOld;
7399     }
7400   }
7401   Remove (w);
7402   return etp;
7403 }
7404 
7405 extern CharPtr HandleExistingText (CharPtr existing_text, CharPtr new_text, ExistingTextPtr etp)
7406 {
7407   CharPtr rstring = NULL;
7408   Int4    len;
7409   
7410   if (StringHasNoText (existing_text) || etp == NULL)
7411   {
7412     MemFree (existing_text);
7413     return new_text;
7414   }
7415   switch (etp->existing_text_choice)
7416   {
7417     case eExistingTextChoiceReplaceOld:
7418       /* replace current text with new text */
7419       MemFree (existing_text);
7420       rstring = new_text;
7421       break;
7422     case eExistingTextChoiceLeaveOld:
7423       /* do not change current text */
7424       MemFree (new_text);
7425       rstring = existing_text;
7426       break;
7427     case eExistingTextChoiceAppendSemi:
7428       /* Append new text to current text, separated by semicolon */
7429       len = StringLen (new_text) + StringLen (existing_text) + 4;
7430       rstring = MemNew (len);
7431       if (rstring != NULL) {
7432         StringCpy (rstring, existing_text);
7433         StringCat (rstring, "; ");
7434         StringCat (rstring, new_text);
7435         MemFree (new_text);
7436         MemFree (existing_text);
7437       }
7438       break;
7439     case eExistingTextChoiceAppendSpace:
7440       /* Append new text to current text, separated by space */
7441       len = StringLen (new_text) + StringLen (existing_text) + 3;
7442       rstring = MemNew (len);
7443       if (rstring != NULL) {
7444         StringCpy (rstring, existing_text);
7445         StringCat (rstring, " ");
7446         StringCat (rstring, new_text);
7447         MemFree (new_text);
7448         MemFree (existing_text);
7449       }
7450       break;
7451     case eExistingTextChoiceAppendColon:
7452       /* Append new text to current text, separated by colon */
7453       len = StringLen (new_text) + StringLen (existing_text) + 4;
7454       rstring = MemNew (len);
7455       if (rstring != NULL) {
7456         StringCpy (rstring, existing_text);
7457         StringCat (rstring, ": ");
7458         StringCat (rstring, new_text);
7459         MemFree (new_text);
7460         MemFree (existing_text);
7461       }
7462       break;
7463     case eExistingTextChoiceAppendNone:
7464       /* Append new text to current text, no delimiter */
7465       len = StringLen (new_text) + StringLen (existing_text) + 1;
7466       rstring = MemNew (len);
7467       if (rstring != NULL) {
7468         StringCpy (rstring, existing_text);
7469         StringCat (rstring, new_text);
7470         MemFree (new_text);
7471         MemFree (existing_text);
7472       }
7473       break;
7474     case eExistingTextChoicePrefixSemi:
7475       /* Prepend new text to current text, separated by semicolon */
7476       len = StringLen (new_text) + StringLen (existing_text) + 4;
7477       rstring = MemNew (len);
7478       if (rstring != NULL) {
7479         StringCpy (rstring, new_text);
7480         StringCat (rstring, "; ");
7481         StringCat (rstring, existing_text);
7482         MemFree (new_text);
7483         MemFree (existing_text);
7484       }
7485       break;
7486     case eExistingTextChoicePrefixSpace:
7487       /* Prepend new text to current text, separated by space */
7488       len = StringLen (new_text) + StringLen (existing_text) + 3;
7489       rstring = MemNew (len);
7490       if (rstring != NULL) {
7491         StringCpy (rstring, new_text);
7492         StringCat (rstring, " ");
7493         StringCat (rstring, existing_text);
7494         MemFree (new_text);
7495         MemFree (existing_text);
7496       }
7497       break;
7498     case eExistingTextChoicePrefixColon:
7499       /* Prepend new text to current text, separated by colon */
7500       len = StringLen (new_text) + StringLen (existing_text) + 4;
7501       rstring = MemNew (len);
7502       if (rstring != NULL) {
7503         StringCpy (rstring, new_text);
7504         StringCat (rstring, ": ");
7505         StringCat (rstring, existing_text);
7506         MemFree (new_text);
7507         MemFree (existing_text);
7508       }
7509       break;
7510     case eExistingTextChoicePrefixNone:
7511       /* prefix current text with new text */
7512       len = StringLen (new_text) + StringLen (existing_text) + 1;
7513       rstring = MemNew (len);
7514       if (rstring != NULL) {
7515         StringCpy (rstring, new_text);
7516         StringCat (rstring, existing_text);
7517         MemFree (new_text);
7518         MemFree (existing_text);
7519       }
7520       break;    
7521   }
7522   return rstring;
7523 }
7524 
7525 
7526 /* Move EditApply data and dialog here */
7527 extern EditApplyPtr EditApplyFree (EditApplyPtr eap)
7528 {
7529   if (eap != NULL)
7530   {
7531     eap->find_txt = MemFree (eap->find_txt);
7532     eap->repl_txt = MemFree (eap->repl_txt);
7533     eap->apply_txt = MemFree (eap->apply_txt);
7534     eap = MemFree (eap);
7535   }
7536   return eap;
7537 }
7538 
7539 
7540 extern EditApplyPtr EditApplyNew (void)
7541 {
7542   EditApplyPtr eap;
7543 
7544   eap = (EditApplyPtr) MemNew (sizeof (EditApplyData));
7545   eap->find_location = EditApplyFindLocation_anywhere;
7546   return eap;
7547 }
7548 
7549 
7550 typedef struct EditApplydlg
7551 {
7552   DIALOG_MESSAGE_BLOCK
7553   TexT           find_txt;
7554   TexT           repl_txt;
7555   TexT           apply_txt;
7556 
7557   DialoG         find_dlg;
7558   DialoG         repl_dlg;
7559   DialoG         apply_dlg;
7560 
7561   Int4           action_choice;
7562   GrouP          location_choice;
7563   Nlm_ChangeNotifyProc     change_notify;
7564   Pointer                  change_userdata;
7565 } EditApplyDlgData, PNTR EditApplyDlgPtr;
7566 
7567 static void ResetEditApplyDlg (EditApplyDlgPtr dlg)
7568 {
7569   if (dlg != NULL)
7570   {
7571     if (dlg->find_txt != NULL)
7572     {
7573       SetTitle (dlg->find_txt, "");
7574     }
7575     if (dlg->repl_txt != NULL)
7576     {
7577       SetTitle (dlg->repl_txt, "");
7578     }
7579     if (dlg->apply_txt != NULL)
7580     {
7581       SetTitle (dlg->apply_txt, "");
7582     }
7583     if (dlg->location_choice != NULL) {
7584       SetValue (dlg->location_choice, EditApplyFindLocation_anywhere);
7585     }
7586 
7587     PointerToDialog (dlg->find_dlg, NULL);
7588     PointerToDialog (dlg->repl_dlg, NULL);
7589     PointerToDialog (dlg->apply_dlg, NULL);
7590 
7591   }
7592 }
7593 
7594 static void EditApplyDialogChangeText (TexT t)
7595 {
7596   EditApplyDlgPtr dlg;
7597 
7598   dlg = (EditApplyDlgPtr) GetObjectExtra (t);
7599   if (dlg != NULL && dlg->change_notify != NULL)
7600   {
7601     (dlg->change_notify)(dlg->change_userdata);
7602   }
7603 }
7604 
7605 static void EditApplyToDialog (DialoG d, Pointer userdata)
7606 {
7607   EditApplyDlgPtr dlg;
7608   EditApplyPtr    data;
7609   ValNode         vn;
7610   
7611   dlg = (EditApplyDlgPtr) GetObjectExtra (d);
7612   if (dlg == NULL)
7613   {
7614     return;
7615   }
7616   
7617   ResetEditApplyDlg (dlg);
7618   data = (EditApplyPtr) userdata;
7619 
7620   vn.next = NULL;
7621   vn.choice = 0;
7622 
7623   if (data != NULL)
7624   {
7625     if (!StringHasNoText (data->find_txt))
7626     {
7627       if (dlg->find_txt != NULL)
7628       {
7629         SetTitle (dlg->find_txt, data->find_txt);
7630       }
7631       else if (dlg->find_dlg != NULL)
7632       {
7633         vn.data.ptrvalue = data->find_txt;
7634         PointerToDialog (dlg->find_dlg, &vn);
7635       }
7636     }
7637 
7638     if (!StringHasNoText (data->repl_txt))
7639     {
7640       if (dlg->repl_txt != NULL) 
7641       {
7642         SetTitle (dlg->repl_txt, data->repl_txt);
7643       }
7644       else if (dlg->repl_dlg != NULL)
7645       {
7646         vn.data.ptrvalue = data->repl_txt;
7647         PointerToDialog (dlg->repl_dlg, &vn);
7648       }
7649     }
7650 
7651     if (!StringHasNoText (data->apply_txt))
7652     {
7653       if (dlg->apply_txt != NULL)
7654       {
7655         SetTitle (dlg->apply_txt, data->apply_txt);
7656       }
7657       else if (dlg->apply_dlg != NULL)
7658       {
7659         vn.data.ptrvalue = data->apply_txt;
7660         PointerToDialog (dlg->apply_dlg, &vn);
7661       }
7662     }
7663 
7664     if (dlg->location_choice != NULL) {
7665       SetValue (dlg->location_choice, data->find_location);
7666     }
7667   }
7668 }
7669 
7670 static Pointer DialogToEditApply (DialoG d)
7671 {
7672   EditApplyDlgPtr dlg;
7673   EditApplyPtr    data;
7674   ValNodePtr      vnp;
7675   
7676   dlg = (EditApplyDlgPtr) GetObjectExtra (d);
7677   if (dlg == NULL)
7678   {
7679     return NULL;
7680   }
7681   
7682   data = (EditApplyPtr) MemNew (sizeof (EditApplyData));
7683   if (data != NULL)
7684   {
7685     if (dlg->find_txt != NULL)
7686     {
7687       data->find_txt = JustSaveStringFromText (dlg->find_txt);
7688     }
7689     else if (dlg->find_dlg != NULL)
7690     {
7691       vnp = (ValNodePtr) DialogToPointer (dlg->find_dlg);
7692       if (vnp != NULL)
7693       {
7694         data->find_txt = StringSave (vnp->data.ptrvalue);
7695       }
7696       vnp = ValNodeFreeData (vnp);
7697     }
7698 
7699     if (dlg->repl_txt != NULL)
7700     {
7701       data->repl_txt = JustSaveStringFromText (dlg->repl_txt);
7702     }
7703     else if (dlg->repl_dlg != NULL)
7704     {
7705       vnp = (ValNodePtr) DialogToPointer (dlg->repl_dlg);
7706       if (vnp != NULL)
7707       {
7708         data->repl_txt = StringSave (vnp->data.ptrvalue);
7709       }
7710       vnp = ValNodeFreeData (vnp);
7711     }
7712 
7713     if (dlg->apply_txt != NULL)
7714     {
7715       data->apply_txt = JustSaveStringFromText (dlg->apply_txt);
7716     }
7717     else if (dlg->apply_dlg != NULL)
7718     {
7719       vnp = (ValNodePtr) DialogToPointer (dlg->apply_dlg);
7720       if (vnp != NULL)
7721       {
7722         data->apply_txt = StringSave (vnp->data.ptrvalue);
7723       }
7724       vnp = ValNodeFreeData (vnp);
7725     }
7726 
7727     if (dlg->location_choice != NULL) {
7728       data->find_location = (EditApplyFindLocation) GetValue (dlg->location_choice);
7729     } else {
7730       data->find_location = EditApplyFindLocation_anywhere;
7731     }
7732   }
7733   return data;
7734 }
7735 
7736 
7737 static void EditApplyMessage (DialoG d, Int2 mssg)
7738 
7739 {
7740   EditApplyDlgPtr  dlg;
7741 
7742   dlg = (EditApplyDlgPtr) GetObjectExtra (d);
7743   if (dlg != NULL) {
7744     switch (mssg) 
7745     {
7746       case VIB_MSG_INIT :
7747         /* reset list */
7748         ResetEditApplyDlg (dlg);
7749         break;
7750       case VIB_MSG_ENTER :
7751         if (dlg->find_txt != NULL)
7752         {
7753           Select (dlg->find_txt);
7754         }
7755         else if (dlg->apply_txt != NULL)
7756         {
7757           Select (dlg->apply_txt);
7758         }
7759         else if (dlg->find_dlg != NULL)
7760         {
7761           Select (dlg->find_dlg);
7762         }
7763         else if (dlg->apply_dlg != NULL)
7764         {
7765           Select (dlg->apply_dlg);
7766         }
7767         break;
7768       default :
7769         break;
7770     }
7771   }
7772 }
7773 
7774 static ValNodePtr TestEditApply (DialoG d)
7775 {
7776   EditApplyDlgPtr dlg;
7777   ValNodePtr      total_err_list = NULL, err_list;
7778   
7779   dlg = (EditApplyDlgPtr) GetObjectExtra (d);
7780   if (dlg == NULL)
7781   {
7782     return FALSE;
7783   }
7784 
7785   if (dlg->action_choice == eEditApplyChoice_Apply)
7786   {
7787     if (dlg->apply_dlg == NULL) 
7788     {
7789       if (TextHasNoText (dlg->apply_txt))
7790       {
7791         ValNodeAddPointer (&total_err_list, 0, StringSave ("apply text"));
7792       }
7793     }
7794     else
7795     {
7796       total_err_list = TestDialog (dlg->apply_dlg);
7797     }
7798   }
7799   else if (dlg->action_choice == eEditApplyChoice_Edit)
7800   {
7801     if (dlg->find_dlg == NULL)
7802     {
7803       if (TextHasNoText (dlg->find_txt))
7804       {
7805         ValNodeAddPointer (&total_err_list, 0, StringSave ("find text"));
7806       }
7807     }
7808     else 
7809     {
7810       total_err_list = TestDialog (dlg->find_dlg);
7811       err_list = TestDialog (dlg->repl_dlg);
7812       ValNodeLink (&total_err_list, err_list);
7813     }
7814   }
7815   return total_err_list;
7816 }
7817 
7818 static void EditApplyDialogCopy (ButtoN b)
7819 {
7820   EditApplyDlgPtr dlg;
7821   CharPtr         str = NULL;
7822 
7823   dlg = (EditApplyDlgPtr) GetObjectExtra (b);
7824   if (dlg == NULL)
7825   {
7826     return;
7827   }
7828   str = JustSaveStringFromText (dlg->find_txt);
7829   SetTitle (dlg->repl_txt, str);
7830   str = MemFree (str);
7831 }
7832 
7833 extern DialoG EditApplyDialog 
7834 (GrouP                    h,
7835  Int4                     action_choice, 
7836  CharPtr                  apply_label,
7837  ValNodePtr               choice_list,
7838  Nlm_ChangeNotifyProc     change_notify,
7839  Pointer                  change_userdata)
7840 {
7841   EditApplyDlgPtr dlg;
7842   GrouP           p, p1 = NULL;
7843   ButtoN          b;
7844   ValNodePtr      cpy;
7845   
7846   dlg = (EditApplyDlgPtr) MemNew (sizeof (EditApplyDlgData));
7847   if (dlg == NULL)
7848   {
7849     return NULL;
7850   }
7851 
7852   p = HiddenGroup (h, -1, 0, NULL);
7853   SetObjectExtra (p, dlg, StdCleanupExtraProc);
7854   SetGroupSpacing (p, 10, 10);
7855 
7856   dlg->dialog = (DialoG) p;
7857   dlg->todialog = EditApplyToDialog;
7858   dlg->fromdialog = DialogToEditApply;
7859   dlg->dialogmessage = EditApplyMessage;
7860   dlg->testdialog = TestEditApply;
7861   dlg->action_choice = action_choice;
7862   dlg->change_notify = change_notify;
7863   dlg->change_userdata = change_userdata;
7864 
7865   if (choice_list == NULL)
7866   {
7867     p1 = HiddenGroup (p, 3, 0, NULL);
7868     SetGroupSpacing (p1, 10, 10);
7869 
7870     if (action_choice == eEditApplyChoice_Apply)
7871     {
7872       StaticPrompt (p1, apply_label, 0, dialogTextHeight, systemFont, 'r');
7873       dlg->apply_txt = DialogText (p1, "", 20, EditApplyDialogChangeText);
7874       SetObjectExtra (dlg->apply_txt, dlg, NULL);
7875       dlg->location_choice = NULL;
7876     }
7877     else if (action_choice == eEditApplyChoice_Edit)
7878     {
7879       StaticPrompt (p1, "Find", 0, dialogTextHeight, systemFont, 'r');
7880       dlg->find_txt = DialogText (p1, "", 18, EditApplyDialogChangeText);
7881       SetObjectExtra (dlg->find_txt, dlg, NULL);
7882       b = PushButton (p1, "Copy", EditApplyDialogCopy);
7883       SetObjectExtra (b, dlg, NULL);
7884       Hide (b);
7885       StaticPrompt (p1, "Replace", 0, dialogTextHeight, systemFont, 'r');
7886       dlg->repl_txt = DialogText (p1, "", 18, EditApplyDialogChangeText);
7887       SetObjectExtra (dlg->repl_txt, dlg, NULL);
7888       b = PushButton (p1, "Copy", EditApplyDialogCopy);
7889       SetObjectExtra (b, dlg, NULL);
7890 
7891       dlg->location_choice = HiddenGroup (p, 3, 0, NULL);
7892       RadioButton (dlg->location_choice, "Anywhere in field");
7893       RadioButton (dlg->location_choice, "At the beginning of the field");
7894       RadioButton (dlg->location_choice, "At the end of the field");
7895       SetValue (dlg->location_choice, EditApplyFindLocation_anywhere);
7896     }
7897   }
7898   else
7899   {
7900     if (action_choice == eEditApplyChoice_Apply)
7901     {
7902       p1 = HiddenGroup (p, 1, 0, NULL);
7903       SetGroupSpacing (p1, 10, 10);
7904       if (!StringHasNoText (apply_label))
7905       {
7906         StaticPrompt (p1, apply_label, 0, dialogTextHeight, systemFont, 'r');
7907       }
7908       cpy = ValNodeDupStringList (choice_list);
7909       dlg->apply_dlg = ValNodeSelectionDialog (p1, cpy, 6,
7910                                                ValNodeStringName,
7911                                                ValNodeSimpleDataFree,
7912                                                ValNodeStringCopy,
7913                                                ValNodeStringMatch,
7914                                                apply_label,
7915                                                dlg->change_notify, dlg->change_userdata, FALSE);
7916     }
7917     else if (action_choice == eEditApplyChoice_Edit)
7918     {
7919       p1 = HiddenGroup (p, 2, 0, NULL);
7920       SetGroupSpacing (p1, 10, 10);
7921       StaticPrompt (p1, "From", 0, dialogTextHeight, systemFont, 'r');
7922       StaticPrompt (p1, "To", 0, dialogTextHeight, systemFont, 'r');
7923 
7924       cpy = ValNodeDupStringList (choice_list);
7925       dlg->find_dlg = ValNodeSelectionDialog (p1, cpy, 6,
7926                                                ValNodeStringName,
7927                                                ValNodeSimpleDataFree,
7928                                                ValNodeStringCopy,
7929                                                ValNodeStringMatch,
7930                                                "Original",
7931                                                dlg->change_notify, dlg->change_userdata, FALSE);
7932       cpy = ValNodeDupStringList (choice_list);
7933       dlg->repl_dlg = ValNodeSelectionDialog (p1, cpy, 6,
7934                                                ValNodeStringName,
7935                                                ValNodeSimpleDataFree,
7936                                                ValNodeStringCopy,
7937                                                ValNodeStringMatch,
7938                                                "New",
7939                                                dlg->change_notify, dlg->change_userdata, FALSE);
7940 
7941     }
7942     dlg->location_choice = NULL;
7943   }
7944   AlignObjects (ALIGN_CENTER, (HANDLE) p1, (HANDLE) dlg->location_choice, NULL);
7945 
7946   return (DialoG) p;
7947 }
7948 
7949 
7950 /* Global Inference Editor Dialog */
7951 
7952 extern InferenceParsePtr ParseInferenceText (CharPtr inference)
7953 {
7954   CharPtr cp1, cp2;
7955   Int4    len;
7956   InferenceParsePtr ipp;
7957 
7958   if (StringHasNoText (inference))
7959   {
7960     return NULL;
7961   }
7962 
7963   cp1 = StringChr (inference, ':');
7964   if (cp1 == NULL)  
7965   {
7966     return NULL;
7967   }
7968   cp2 = StringChr (cp1 + 1, ':');
7969   if (cp2 == NULL)
7970   {
7971     return NULL;
7972   }
7973 
7974   ipp = (InferenceParsePtr) MemNew (sizeof (InferenceParseData));
7975   ipp->second_field = StringSave (cp2 + 1);
7976 
7977   len = cp2 - cp1;
7978   ipp->first_field = (CharPtr) MemNew (sizeof (Char) * len);
7979   StringNCpy (ipp->first_field, cp1 + 1, len - 1);
7980   ipp->first_field[len - 1] = 0;
7981 
7982   /* look for same species */
7983   cp2 = StringISearch (inference, "(same species)");
7984   if (cp2 != NULL && cp2 < cp1)
7985   {
7986     ipp->same_species = TRUE;
7987     cp1 = cp2;
7988   } 
7989   else
7990   {
7991     ipp->same_species = FALSE;
7992   }
7993   len = cp1 - inference + 1;
7994   ipp->category = (CharPtr) MemNew (sizeof (Char) * len);
7995   StringNCpy (ipp->category, inference, len - 1);
7996   ipp->category[len - 1] = 0;
7997   TrimSpacesAroundString (ipp->category);
7998   TrimSpacesAroundString (ipp->first_field);
7999   TrimSpacesAroundString (ipp->second_field);
8000 
8001   return ipp;  
8002 }
8003 
8004 
8005 extern CharPtr InferenceTextFromStruct (InferenceParsePtr ipp)
8006 {
8007   Int4 len;
8008   CharPtr inference = NULL;
8009   CharPtr same_sp = " (same species)";
8010 
8011   if (ipp == NULL) return NULL;
8012 
8013   len = StringLen (ipp->category) + StringLen (ipp->first_field) + StringLen (ipp->second_field)
8014         + 3;
8015   if (ipp->same_species)
8016   {
8017     len += StringLen (same_sp);
8018   }
8019 
8020   inference = (CharPtr) MemNew (sizeof (Char) * len);
8021   sprintf (inference, "%s%s:%s:%s", ipp->category == NULL ? "" : ipp->category,
8022                                     ipp->same_species ? same_sp : "",
8023                                     ipp->first_field == NULL ? "" : ipp->first_field,
8024                                     ipp->second_field == NULL ? "" : ipp->second_field);
8025   return inference;
8026 }
8027 
8028 
8029 typedef enum {
8030   eInferenceCategorySimilarTo = 0,
8031   eInferenceCategoryProgram,
8032   eInferenceCategoryAbInitio,
8033   eNumInferenceCategories } EInferenceCategoryType;
8034 
8035 
8036 static Int4 GetCategoryTypeFromNum (Int4 num)
8037 {
8038   if (num > 0 && num < 8) 
8039   {
8040     return eInferenceCategorySimilarTo;
8041   }
8042   else if (num > 7 && num < 11)
8043   {
8044     return eInferenceCategoryProgram;
8045   }
8046   else if (num == 11)
8047   {
8048     return eInferenceCategoryAbInitio;
8049   }
8050   else
8051   {
8052     return -1;
8053   }
8054 }
8055 
8056 
8057 static Int4 GetCategoryNumFromName (CharPtr category)
8058 {
8059   Int4 i;
8060 
8061   if (StringHasNoText (category)) 
8062   {
8063     return -1;
8064   }
8065 
8066   for (i = 0; inference_alist[i].name != NULL; i++)
8067   {
8068     if (StringICmp (inference_alist[i].name, category) == 0)
8069     {
8070       return i;
8071     }
8072   }
8073   return -1;
8074 }
8075 
8076 
8077 extern InferenceFieldEditPtr InferenceFieldEditFree (InferenceFieldEditPtr ifep)
8078 {
8079   if (ifep != NULL)
8080   {
8081     ifep->edit_apply = EditApplyFree (ifep->edit_apply);
8082     ifep = MemFree (ifep);
8083   }
8084   return ifep;
8085 }
8086 
8087 extern InferenceEditPtr InferenceEditFree (InferenceEditPtr iep)
8088 {
8089   if (iep != NULL)
8090   {
8091     iep->field_edit = InferenceFieldEditFree (iep->field_edit);
8092     iep = MemFree (iep);
8093   }
8094   return iep;
8095 }
8096 
8097 typedef struct inferencefieldeditdialog
8098 {
8099   DIALOG_MESSAGE_BLOCK
8100 
8101   PopuP  field_category;
8102   PopuP  field_list[eNumInferenceCategories];
8103   DialoG field_editors[eNumInferenceCategories * 2];
8104   Nlm_ChangeNotifyProc     change_notify;
8105   Pointer                  change_userdata;
8106 
8107 } InferenceFieldEditDialogData, PNTR InferenceFieldEditDialogPtr;
8108 
8109 
8110 static Pointer InferenceFieldEditDataFromDialog (DialoG d)
8111 {
8112   InferenceFieldEditDialogPtr dlg;
8113   UIEnum                      val;
8114   Int4                        i, j;
8115   InferenceFieldEditPtr       data = NULL;
8116 
8117   dlg = (InferenceFieldEditDialogPtr) GetObjectExtra (d);
8118   if (dlg == NULL) return NULL;
8119 
8120   if (GetEnumPopup (dlg->field_category, inference_alist, &val)
8121       && val > 0
8122       && (i = GetCategoryTypeFromNum (val)) > -1
8123       && (j = GetValue (dlg->field_list[i])) > 0
8124       && j < 3)
8125   {
8126     data = (InferenceFieldEditPtr) MemNew (sizeof (InferenceFieldEditData));
8127     data->field_category = inferencePrefix[val];
8128     data->field_choice = j - 1;
8129     data->edit_apply = DialogToPointer (dlg->field_editors[2 * i + j - 1]);
8130   }
8131   return data;
8132 }
8133 
8134 
8135 static void ChangeInferenceFieldChoice (PopuP p)
8136 {
8137   InferenceFieldEditDialogPtr dlg;
8138   UIEnum                      val;
8139   Int4                        i, j;
8140 
8141   dlg = (InferenceFieldEditDialogPtr) GetObjectExtra (p);
8142   if (dlg == NULL) return;
8143 
8144   for (i = eInferenceCategorySimilarTo;
8145        i <= eInferenceCategoryAbInitio;
8146        i++)
8147   {
8148     Hide (dlg->field_list[i]);
8149     Hide (dlg->field_editors[2 * i]);
8150     Hide (dlg->field_editors[2 * i + 1]);
8151   }
8152 
8153   if (GetEnumPopup (dlg->field_category, inference_alist, &val)
8154       && val > 0
8155       && (i = GetCategoryTypeFromNum (val)) > -1)
8156   {
8157     Show (dlg->field_list[i]);
8158     j = GetValue (dlg->field_list[i]);
8159     if (j > 0 && j < 3)
8160     {
8161       Show (dlg->field_editors[2 * i + j - 1]);
8162     }
8163   }
8164 
8165   if (dlg->change_notify != NULL) 
8166   {
8167     (dlg->change_notify)(dlg->change_userdata);
8168   }
8169 }
8170 
8171 static ValNodePtr MakeValNodeListFromEnum ( EnumFieldAssocPtr al)
8172 {
8173   EnumFieldAssocPtr efap;
8174   ValNodePtr        list;
8175 
8176   efap = al;
8177   list = NULL;
8178   while (efap->name != NULL)
8179   {
8180     ValNodeAddStr (&list, efap->value, StringSave (efap->name));
8181     efap ++;
8182   }
8183   return list;
8184 }
8185 
8186 
8187 static DialoG 
8188 CreateInferenceFieldEditApplyDialog 
8189 (GrouP                h,
8190  Int4                 action_choice,
8191  Nlm_ChangeNotifyProc change_notify,
8192  Pointer              change_userdata)
8193 {
8194   InferenceFieldEditDialogPtr dlg;
8195   GrouP                       p, k;
8196   Int4                        i;
8197   ValNodePtr                  choice_list;
8198 
8199   dlg = (InferenceFieldEditDialogPtr) MemNew (sizeof (InferenceFieldEditDialogData));
8200   if (dlg == NULL)
8201   {
8202     return NULL;
8203   }
8204   p = HiddenGroup (h, 3, 0, NULL);
8205   SetObjectExtra (p, dlg, StdCleanupExtraProc);
8206   SetGroupSpacing (p, 10, 10);
8207   
8208   dlg->dialog = (DialoG) p;
8209   dlg->todialog = NULL;
8210   dlg->fromdialog = InferenceFieldEditDataFromDialog;
8211   dlg->dialogmessage = NULL;
8212   dlg->testdialog = NULL;
8213   
8214   dlg->change_notify = change_notify;
8215   dlg->change_userdata = change_userdata;
8216 
8217   StaticPrompt (p, "Category", 0, popupMenuHeight, programFont, 'c');
8218   StaticPrompt (p, "Field", 0, popupMenuHeight, programFont, 'c');
8219   if (action_choice == eEditApplyChoice_Apply) 
8220   {
8221     StaticPrompt (p, "New Value", 0, popupMenuHeight, programFont, 'c');
8222   }
8223   else
8224   {
8225     StaticPrompt (p, "Convert", 0, popupMenuHeight, programFont, 'c');
8226   }
8227 
8228   dlg->field_category = PopupList (p, TRUE, ChangeInferenceFieldChoice);
8229   SetObjectExtra (dlg->field_category, dlg, NULL);
8230   InitEnumPopup (dlg->field_category, inference_alist, NULL);
8231 
8232 
8233   k = HiddenGroup (p, 0, 0, NULL);
8234   dlg->field_list[eInferenceCategorySimilarTo] = PopupList (k, TRUE, ChangeInferenceFieldChoice);
8235   SetObjectExtra (dlg->field_list[eInferenceCategorySimilarTo], dlg, NULL);
8236   PopupItem (dlg->field_list[eInferenceCategorySimilarTo], "Database");
8237   PopupItem (dlg->field_list[eInferenceCategorySimilarTo], "Accession");
8238   
8239   dlg->field_list[eInferenceCategoryProgram] = PopupList (k, TRUE, ChangeInferenceFieldChoice);
8240   SetObjectExtra (dlg->field_list[eInferenceCategoryProgram], dlg, NULL);
8241   PopupItem (dlg->field_list[eInferenceCategoryProgram], "Program or Database");
8242   PopupItem (dlg->field_list[eInferenceCategoryProgram], "Version or Accession");
8243   
8244   dlg->field_list[eInferenceCategoryAbInitio] = PopupList (k, TRUE, ChangeInferenceFieldChoice);
8245   SetObjectExtra (dlg->field_list[eInferenceCategoryAbInitio], dlg, NULL);
8246   PopupItem (dlg->field_list[eInferenceCategoryAbInitio], "Program");
8247   PopupItem (dlg->field_list[eInferenceCategoryAbInitio], "Program Version");
8248 
8249   k = HiddenGroup (p, 0, 0, NULL);
8250   i = 0;
8251   choice_list = MakeValNodeListFromEnum (accn_type_alist);
8252   dlg->field_editors[i++] = EditApplyDialog (k, action_choice, "", choice_list, change_notify, change_userdata);
8253   dlg->field_editors[i++] = EditApplyDialog (k, action_choice, "", NULL, change_notify, change_userdata);
8254   dlg->field_editors[i++] = EditApplyDialog (k, action_choice, "", NULL, change_notify, change_userdata);
8255   dlg->field_editors[i++] = EditApplyDialog (k, action_choice, "", NULL, change_notify, change_userdata);
8256   choice_list = MakeValNodeListFromEnum (program_alist);
8257   dlg->field_editors[i++] = EditApplyDialog (k, action_choice, "", choice_list, change_notify, change_userdata);
8258   dlg->field_editors[i++] = EditApplyDialog (k, action_choice, "", NULL, change_notify, change_userdata);
8259 
8260   ChangeInferenceFieldChoice (dlg->field_category);
8261   return (DialoG) p;
8262 }
8263 
8264 
8265 typedef struct inferenceeditdialog {
8266   DIALOG_MESSAGE_BLOCK
8267   PopuP action;
8268   GrouP action_pages[eNumInferenceEditActions];
8269   PopuP category_from;
8270   PopuP category_to;
8271   
8272   DialoG apply_field;
8273   DialoG edit_field;
8274 
8275   Nlm_ChangeNotifyProc change_notify;
8276   Pointer              change_userdata;
8277 
8278 } InferenceEditDialogData, PNTR InferenceEditDialogPtr;
8279 
8280 
8281 static Pointer InferenceEditDataFromDialog (DialoG d)
8282 {
8283   InferenceEditDialogPtr dlg;
8284   InferenceEditPtr       data;
8285   Int4                   i;
8286 
8287   dlg = (InferenceEditDialogPtr) GetObjectExtra (d);
8288   if (dlg == NULL) return NULL;
8289 
8290   data = (InferenceEditPtr) MemNew (sizeof (InferenceEditData));
8291   if (data == NULL) return NULL;
8292 
8293   data->action = (EInferenceEditAction) (GetValue (dlg->action) - 1);
8294 
8295   switch (data->action)
8296   {
8297     case eInferenceRemove:
8298       /* no other data needed */
8299       break;
8300     case eInferenceEditCategory:
8301       i = GetValue (dlg->category_from);
8302       if (i <= 1) 
8303       {
8304         data->category_from = NULL;
8305       }
8306       else
8307       {
8308         data->category_from = inferencePrefix[i - 2];
8309       }
8310       i = GetValue (dlg->category_to);
8311       if (i < 1)
8312       {
8313         data->category_to = NULL;
8314       }
8315       else
8316       {
8317         data->category_to = inferencePrefix[i - 1];
8318       }
8319       break;
8320     case eInferenceApplyCategoryFields:
8321      data->field_edit = DialogToPointer (dlg->apply_field);
8322      break;
8323     case eInferenceEditCategoryFields:
8324      data->field_edit = DialogToPointer (dlg->edit_field);
8325       break;
8326     default:
8327       break;
8328   }
8329 
8330   return data;
8331 }
8332 
8333 
8334 static void ChangeInferenceEditAction (PopuP p)
8335 {
8336   InferenceEditDialogPtr dlg;
8337   Int4                   i;
8338 
8339   dlg = (InferenceEditDialogPtr) GetObjectExtra (p);
8340   if (dlg == NULL) return;
8341 
8342   ResetClip();
8343   for (i = 0; i < eNumInferenceEditActions; i++)
8344   {
8345     Hide (dlg->action_pages[i]);
8346   }
8347 
8348   i = GetValue (dlg->action);
8349   if (i > 0 && i <= eNumInferenceEditActions)
8350   {
8351     Show (dlg->action_pages[i - 1]);
8352   }
8353 
8354   if (dlg->change_notify != NULL) 
8355   {
8356     (dlg->change_notify) (dlg->change_userdata);
8357   }
8358 }
8359 
8360 
8361 static void ChangeInferenceCategoryChoice (PopuP p)
8362 {
8363   InferenceEditDialogPtr dlg;
8364 
8365   dlg = (InferenceEditDialogPtr) GetObjectExtra (p);
8366   if (dlg == NULL) return;
8367 
8368   if (dlg->change_notify != NULL) 
8369   {
8370     (dlg->change_notify) (dlg->change_userdata);
8371   }
8372 }
8373 
8374 
8375 static ValNodePtr TestInferenceEditDialog (DialoG d)
8376 {
8377   ValNodePtr             err_list = NULL;
8378   InferenceEditPtr       iep;
8379 
8380   iep = DialogToPointer (d);
8381   if (iep == NULL)
8382   {
8383     ValNodeAddPointer (&err_list, 0, "no values");
8384   }
8385   else
8386   {
8387     switch (iep->action)
8388     {
8389       case eInferenceRemove:
8390         /* nothing to check */
8391         break;
8392       case eInferenceEditCategory:
8393         if (StringHasNoText (iep->category_from))
8394         {
8395           ValNodeAddPointer (&err_list, 0, "missing category from");
8396         }
8397         if (StringHasNoText (iep->category_to))
8398         {
8399           ValNodeAddPointer (&err_list, 0, "missing category to");
8400         }
8401         break;
8402       case eInferenceApplyCategoryFields:
8403       case eInferenceEditCategoryFields:
8404         if (iep->field_edit == NULL)
8405         {
8406           ValNodeAddPointer (&err_list, 0, "missing edit data");
8407         }
8408         break;
8409       default:
8410         break;
8411     }
8412   }
8413   iep = InferenceEditFree (iep);
8414 
8415   return err_list;
8416 }
8417 
8418 
8419 extern DialoG CreateInferenceEditDialog 
8420 (GrouP                    h,
8421  Nlm_ChangeNotifyProc     change_notify,
8422  Pointer                  change_userdata)
8423 {
8424   InferenceEditDialogPtr dlg;
8425   GrouP                  p, g;
8426   Int4                   i;
8427   Nlm_EnumFieldAssocPtr  eap;
8428 
8429   dlg = (InferenceEditDialogPtr) MemNew (sizeof (InferenceEditDialogData));
8430   if (dlg == NULL)
8431   {
8432     return NULL;
8433   }
8434   p = HiddenGroup (h, -1, 0, NULL);
8435   SetObjectExtra (p, dlg, StdCleanupExtraProc);
8436   SetGroupSpacing (p, 10, 10);
8437   
8438   dlg->dialog = (DialoG) p;
8439   dlg->todialog = NULL;
8440   dlg->fromdialog = InferenceEditDataFromDialog;
8441   dlg->dialogmessage = NULL;
8442   dlg->testdialog = TestInferenceEditDialog;
8443 
8444   dlg->change_notify = change_notify;
8445   dlg->change_userdata = change_userdata;
8446 
8447   dlg->action = PopupList (p, TRUE, ChangeInferenceEditAction);
8448   SetObjectExtra (dlg->action, dlg, NULL);
8449   PopupItem (dlg->action, "Remove");
8450   PopupItem (dlg->action, "Change Category");
8451   PopupItem (dlg->action, "Apply Category Fields");
8452   PopupItem (dlg->action, "Edit Category Fields");
8453   SetValue (dlg->action, eInferenceRemove + 1);
8454 
8455   g = HiddenGroup (p, 0, 0, NULL);
8456   i = 0;
8457 
8458   /* remove group */
8459   dlg->action_pages[i] = HiddenGroup (g, -1, 0, NULL);
8460   StaticPrompt (dlg->action_pages[i], "Hit Accept to Remove Inferences", 0, popupMenuHeight, programFont, 'c');
8461   i++;
8462 
8463   /* edit category group */
8464   dlg->action_pages[i] = HiddenGroup (g, 2, 0, NULL);
8465   StaticPrompt (dlg->action_pages[i], "Original Category", 0, popupMenuHeight, programFont, 'c');
8466   dlg->category_from = PopupList (dlg->action_pages[i], TRUE, ChangeInferenceCategoryChoice);
8467   SetObjectExtra (dlg->category_from, dlg, NULL);
8468   PopupItem (dlg->category_from, "Any");
8469   eap = inference_alist;
8470   while (eap->name != NULL) {
8471     PopupItem (dlg->category_from, eap->name);
8472     eap++;
8473   }
8474   
8475   StaticPrompt (dlg->action_pages[i], "New Category", 0, popupMenuHeight, programFont, 'c');
8476   dlg->category_to = PopupList (dlg->action_pages[i], TRUE, ChangeInferenceCategoryChoice);
8477   SetObjectExtra (dlg->category_to, dlg, NULL);
8478   InitEnumPopup (dlg->category_to, inference_alist, NULL);
8479   i++;
8480 
8481   dlg->action_pages[i] = HiddenGroup (g, 0, 0, NULL);
8482   dlg->apply_field = CreateInferenceFieldEditApplyDialog (dlg->action_pages[i], eEditApplyChoice_Apply, change_notify, change_userdata);
8483   i++;
8484   
8485   dlg->action_pages[i] = HiddenGroup (g, 0, 0, NULL);
8486   dlg->edit_field = CreateInferenceFieldEditApplyDialog (dlg->action_pages[i], eEditApplyChoice_Edit, change_notify, change_userdata);
8487   i++;
8488   
8489   AlignObjects (ALIGN_CENTER, (HANDLE) dlg->action_pages[0],
8490                               (HANDLE) dlg->action_pages[1],
8491                               (HANDLE) dlg->action_pages[2],
8492                               (HANDLE) dlg->action_pages[3],
8493                               NULL);
8494   
8495   AlignObjects (ALIGN_CENTER, (HANDLE) dlg->action, (HANDLE) g, NULL);
8496 
8497   ChangeInferenceEditAction (dlg->action);
8498 
8499   return (DialoG) p;
8500 }
8501 
8502 
8503 /* This section of code is for handling ClickableLists */
8504 
8505 typedef struct clickableitemlist
8506 {
8507   DIALOG_MESSAGE_BLOCK
8508   DoC doc;
8509 
8510   Nlm_ParData par_fmt;
8511   Nlm_ColData col_fmt [4];
8512 
8513   ClickableCallback single_click_callback;
8514   ClickableCallback double_click_callback;
8515   Pointer           click_callback_data;
8516   GetClickableItemText get_item_text;
8517   ValNodePtr           item_list;
8518   Int2                 selected;
8519 } ClickableItemListDlgData, PNTR ClickableItemListDlgPtr;
8520 
8521 static void PointerToClickableItemListDlg (DialoG d, Pointer data)
8522 {
8523   ClickableItemListDlgPtr dlg;
8524   ValNodePtr              vnp;
8525   CharPtr                 row_text;
8526   Int2                 numItems;
8527   RecT                 r;
8528 
8529   dlg = (ClickableItemListDlgPtr) GetObjectExtra (d);
8530   if (dlg == NULL) return;
8531 
8532   Reset (dlg->doc);
8533   
8534   if (dlg->get_item_text == NULL)
8535   {
8536     return;
8537   }
8538 
8539   ObjectRect (dlg->doc, &r);
8540   InsetRect (&r, 4, 4);
8541   
8542   dlg->col_fmt[0].pixWidth = 5 * stdCharWidth;
8543   dlg->col_fmt[1].pixWidth = (r.right - r.left - dlg->col_fmt[0].pixWidth) / 3;
8544   dlg->col_fmt[2].pixWidth = (r.right - r.left - dlg->col_fmt[0].pixWidth) / 3;
8545   dlg->col_fmt[3].pixWidth = (r.right - r.left - dlg->col_fmt[0].pixWidth) / 3;
8546 
8547   dlg->item_list = ClickableItemObjectListFree (dlg->item_list);
8548   dlg->item_list = (ValNodePtr) data; 
8549  
8550   if (dlg->item_list == NULL)
8551   {
8552     AppendText (dlg->doc, "No items listed", NULL, NULL, programFont);
8553   } else {
8554     for (vnp = dlg->item_list; vnp != NULL; vnp = vnp->next) {
8555       row_text = dlg->get_item_text (vnp);
8556       if (row_text != NULL)
8557       {
8558         if (vnp->choice == OBJ_SEQFEAT)
8559         {
8560           AppendText (dlg->doc, row_text, &(dlg->par_fmt), dlg->col_fmt, programFont);
8561         }
8562         else
8563         {
8564           AppendText (dlg->doc, row_text, &(dlg->par_fmt), NULL, programFont);
8565         }
8566         row_text = MemFree (row_text);
8567       }
8568     }
8569   }
8570   
8571   GetDocParams (dlg->doc, &numItems, NULL);
8572   UpdateDocument (dlg->doc, 0, numItems);  
8573 }
8574 
8575 
8576 static void ClickClickableItemList (DoC d, PoinT pt)
8577 
8578 {
8579   Int2             item, last_selected, numItems;
8580   Int2             row, i;
8581   ClickableItemListDlgPtr dlg;
8582   ValNodePtr       vnp;
8583 
8584   dlg = GetObjectExtra (d);
8585   if (dlg != NULL) {
8586     MapDocPoint (d, pt, &item, &row, NULL, NULL);
8587     if (item > 0 && row > 0) {  
8588       i = 1;
8589       vnp = dlg->item_list;
8590       while (i < item && vnp != NULL) {
8591         i++;
8592         vnp = vnp->next;
8593       }
8594       if (vnp != NULL) {
8595         last_selected = dlg->selected;
8596         dlg->selected = item;
8597         
8598         if (item != last_selected)
8599         {
8600           GetDocParams (d, &numItems, NULL);
8601           UpdateDocument (d, 0, numItems);
8602         }
8603     
8604         if (dblClick)
8605         {
8606           if (dlg->double_click_callback != NULL) {
8607             (dlg->double_click_callback) (vnp, dlg->click_callback_data);
8608           }
8609         } else {
8610           if (dlg->single_click_callback != NULL) {
8611             (dlg->single_click_callback) (vnp, dlg->click_callback_data);
8612           }
8613         }          
8614       }
8615     }
8616   }
8617 }
8618 
8619 
8620 static void DrawClickableItemList (DoC d, RectPtr r, Int2 item, Int2 firstLine)
8621 
8622 {
8623   ClickableItemListDlgPtr dlg;
8624   RecT             rct;
8625 
8626   dlg = (ClickableItemListDlgPtr) GetObjectExtra (d);
8627   if (dlg != NULL && r != NULL && item > 0 && firstLine == 0) {
8628     rct = *r;
8629   
8630     /* draw selection */
8631     if (item == dlg->selected) {
8632       rct = *r;
8633       rct.right = rct.left + 4;
8634       PaintRect (&rct);
8635     }
8636   }
8637 }
8638 
8639 
8640 static void CleanupClickableItemListDlg (GraphiC g, VoidPtr data)
8641 {
8642   ClickableItemListDlgPtr dlg;
8643 
8644   dlg = (ClickableItemListDlgPtr) data;
8645   if (dlg != NULL) {
8646     dlg->item_list = ClickableItemObjectListFree (dlg->item_list);
8647   } 
8648   StdCleanupExtraProc (g, data);
8649 }
8650 
8651 static DialoG 
8652 ClickableItemListDialog 
8653 (GrouP h,
8654  Int4 width,
8655  GetClickableItemText get_item_text,
8656  ClickableCallback single_click_callback,
8657  ClickableCallback double_click_callback,
8658  Pointer click_callback_data)
8659 {
8660   ClickableItemListDlgPtr dlg;
8661   GrouP                p;
8662   Int4 i;
8663 
8664   dlg = (ClickableItemListDlgPtr) MemNew (sizeof (ClickableItemListDlgData));
8665   p = HiddenGroup (h, -1, 0, NULL);
8666   SetObjectExtra (p, dlg, CleanupClickableItemListDlg);
8667   dlg->dialog = (DialoG) p;
8668   dlg->todialog = PointerToClickableItemListDlg;
8669 
8670   dlg->get_item_text = get_item_text;
8671   dlg->single_click_callback = single_click_callback;
8672   dlg->double_click_callback = double_click_callback;
8673   dlg->click_callback_data = click_callback_data;
8674   /* initialize paragraph format */
8675   dlg->par_fmt.openSpace = FALSE;
8676   dlg->par_fmt.keepWithNext = FALSE;
8677   dlg->par_fmt.keepTogether = FALSE;
8678   dlg->par_fmt.newPage = FALSE;
8679   dlg->par_fmt.tabStops = FALSE;
8680   dlg->par_fmt.minLines = 0;
8681   dlg->par_fmt.minHeight = 0;
8682 
8683   /* initialize column format */
8684   for (i = 0; i < 4; i++) {
8685     dlg->col_fmt[i].pixWidth = 0;
8686     dlg->col_fmt[i].pixInset = 0;
8687     dlg->col_fmt[i].charWidth = 10;
8688     dlg->col_fmt[i].charInset = 0;
8689     dlg->col_fmt[i].font = NULL;
8690     dlg->col_fmt[i].just = 'l';
8691     dlg->col_fmt[i].wrap = 1;
8692     dlg->col_fmt[i].bar = 0;
8693     dlg->col_fmt[i].underline = 0;
8694     dlg->col_fmt[i].left = 0;
8695     dlg->col_fmt[i].last = FALSE;
8696   }
8697   dlg->col_fmt[0].pixInset = 5;
8698   dlg->col_fmt[3].last = TRUE;
8699   
8700   dlg->doc = DocumentPanel (p, width, stdLineHeight * 20);
8701   SetObjectExtra (dlg->doc, dlg, NULL);
8702   SetDocAutoAdjust (dlg->doc, FALSE);
8703   SetDocProcs (dlg->doc, ClickClickableItemList, NULL, NULL, NULL);
8704   SetDocShade (dlg->doc, DrawClickableItemList, NULL, NULL, NULL);
8705 
8706   return (DialoG) p;
8707 }
8708 
8709 typedef struct clickablelist
8710 {
8711   DIALOG_MESSAGE_BLOCK
8712   DoC  doc;
8713   DialoG clickable_item_list;
8714   PrompT title1;
8715   PrompT title2;
8716   PrompT help1;
8717   PrompT help2;
8718   TexT find_txt;
8719 
8720   ClickableCallback item_single_click_callback;
8721   ClickableCallback item_double_click_callback;
8722   Pointer         item_click_callback_data;
8723   GetClickableItemText get_item_text;
8724   Boolean         dblClick;  
8725   Int2            clicked;
8726   Int2            selected;
8727   Int2            item_selected;  
8728   Int4            num_levels;
8729   ValNodePtr      list_list;
8730   Nlm_ColPtr PNTR col_fmt_array_array;
8731 
8732   Int2            text_select_item_start;
8733   Int2            text_select_row_start;
8734   Int2            text_select_char_start;
8735   Int2            text_select_item_stop;
8736   Int2            text_select_row_stop;
8737   Int2            text_select_char_stop;
8738   Int2            text_select_item_anchor;
8739   Int2            text_select_row_anchor;
8740   Int2            text_select_char_anchor;
8741 
8742   Boolean         display_chosen;
8743 } ClickableListData, PNTR ClickableListPtr;
8744 
8745 
8746 static Nlm_ParData clickableParFmt = {FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0};
8747 static Nlm_ColData clickableColFmt[2] = {{16, 0, 0, 0, NULL, 'l', 0,0,0,0, FALSE},
8748                                     {1000, 0, 0, 0, NULL, 'l', 1,0,0,0, TRUE}};
8749 
8750 
8751 static Nlm_ColPtr PNTR FreeColumnFormatArrays (Nlm_ColPtr PNTR col_fmt_array_array, Int4 num_levels)
8752 {
8753   Int4 n;
8754   
8755   if (col_fmt_array_array == NULL || num_levels < 1)
8756   {
8757     return NULL;
8758   }
8759   for (n = 0; n < num_levels; n++)
8760   {
8761     col_fmt_array_array [n] = MemFree (col_fmt_array_array [n]);
8762   }
8763   col_fmt_array_array = MemFree (col_fmt_array_array);
8764   return col_fmt_array_array;
8765 }
8766 
8767 static void CleanupClickableListDialog (GraphiC g, VoidPtr data)
8768 
8769 {
8770   ClickableListPtr dlg;
8771 
8772   dlg = (ClickableListPtr) data;
8773   if (dlg != NULL) {
8774      dlg->col_fmt_array_array = FreeColumnFormatArrays (dlg->col_fmt_array_array, dlg->num_levels);
8775   }
8776   StdCleanupExtraProc (g, data);
8777 }
8778 
8779 
8780 static ClickableItemPtr GetSubItem (ValNodePtr item_list, Int2Ptr pitem)
8781 {
8782   ClickableItemPtr cip = NULL;
8783 
8784   if (item_list == NULL || pitem == NULL)
8785   {
8786     return NULL;
8787   }
8788   while (*pitem > 0 && item_list != NULL)
8789   {
8790     (*pitem)--;
8791     cip = (ClickableItemPtr) item_list->data.ptrvalue;
8792     if (*pitem > 0)
8793     {
8794       if (cip != NULL && cip->expanded)
8795       {
8796         cip = GetSubItem (cip->subcategories, pitem);
8797       }
8798     }
8799     item_list = item_list->next;
8800   }
8801   if (*pitem > 0)
8802   {
8803     cip = NULL;
8804   }
8805   return cip;
8806 }
8807 
8808 static Int4 CountLevels (ValNodePtr item_list)
8809 {
8810   Int4       num, num_sublevels = 0;
8811   ValNodePtr vnp;
8812   ClickableItemPtr cip;
8813   
8814   if (item_list == NULL) 
8815   {
8816     return 0;
8817   }
8818   
8819   for (vnp = item_list; vnp != NULL; vnp = vnp->next)
8820   {
8821     cip = (ClickableItemPtr) vnp->data.ptrvalue;
8822     if (cip == NULL || cip->subcategories == NULL || !cip->expanded)
8823     {
8824       continue;
8825     }
8826     num = CountLevels (cip->subcategories);
8827     if (num > num_sublevels) num_sublevels = num;
8828   }
8829   
8830   /* one level for the top plus levels for the subcategories */
8831 
8832   return 1 + num_sublevels;
8833 }
8834 
8835 
8836 static ClickableItemPtr GetSelectedClickableL