1 /*   sequin4.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:  sequin4.c
27 *
28 * Author:  Jonathan Kans
29 *
30 * Version Creation Date:   6/28/96
31 *
32 * $Revision: 6.510 $
33 *
34 * File Description:
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38 * Date     Name        Description of modification
39 * -------  ----------  -----------------------------------------------------
40 *
41 *
42 * ==========================================================================
43 */
44 
45 #include "sequin.h"
46 #include <ncbilang.h>
47 #include <seqport.h>
48 #include <gather.h>
49 #include <objall.h>
50 #include <objcode.h>
51 #include <utilpub.h>
52 #include <vibrant.h>
53 #include <document.h>
54 #include <toasn3.h>
55 #include <asn2ffp.h>
56 #include <salfiles.h>
57 #include <salsap.h>
58 #include <saledit.h>
59 #include <salign.h>
60 #include <salptool.h>
61 #include <subutil.h>
62 #include <pobutil.h>
63 #include <tfuns.h>
64 #include <edutil.h>
65 #include <biosrc.h>
66 #include <seqgrphx.h>
67 #include <seqmtrx.h>
68 #include <bspview.h>
69 #include <vsmpriv.h>
70 #include <explore.h>
71 #include <alignval.h>
72 #include <alignmgr.h>
73 #include <alignmgr2.h>
74 #include <aliparse.h>
75 #include <spidey.h>
76 #include <ent2api.h>
77 #include <valid.h>
78 #include <sqnutils.h>
79 #include <seqpanel.h>
80 #include <salpanel.h>
81 #include <findrepl.h>
82 #include <macrodlg.h>
83 #include <macroapi.h>
84 
85 static Int2 LIBCALLBACK CreateSegSet (Pointer data);
86 static Int2 LIBCALLBACK FeatToDeltaSeq (Pointer data);
87 static Int2 LIBCALLBACK CopyMasterSourceToSegments (Pointer data);
88 static Int2 LIBCALLBACK OrfFindFunc (Pointer data);
89 
90 #define REGISTER_APPLY_SET_TYPE ObjMgrProcLoadEx (OMPROC_FILTER,"Convert Set Type","ConvertSetType",0,0,0,0,NULL,ApplySetTypeDesktop,PROC_PRIORITY_DEFAULT, "Indexer")
91 
92 #define REGISTER_REMOVESET ObjMgrProcLoadEx (OMPROC_FILTER,"Remove Set","RemoveSet",0,0,0,0,NULL,RemoveSet,PROC_PRIORITY_DEFAULT, "Indexer")
93 
94 #define REGISTER_REMOVESETSINSET ObjMgrProcLoadEx (OMPROC_FILTER,"Remove Sets in Selected Set","RemoveSetsInSelectedSet",0,0,0,0,NULL,RemoveSetsInSelectedSet,PROC_PRIORITY_DEFAULT, "Indexer")
95 
96 #define REGISTER_REPACKAGE_PARTS ObjMgrProcLoadEx (OMPROC_FILTER,"Repackage Segmented Parts","RepackageParts",0,0,0,0,NULL,PackagePartsInPartsSet,PROC_PRIORITY_DEFAULT, "Indexer")
97 
98 #define REGISTER_NORMALIZE_NUCPROT ObjMgrProcLoadEx (OMPROC_FILTER,"Normalize Nuc-Prot","NormalizeNucProts",0,0,0,0,NULL,NormalizeNucProts,PROC_PRIORITY_DEFAULT, "Indexer")
99 
100 #define REGISTER_REMOVE_EXTRANEOUS ObjMgrProcLoadEx (OMPROC_FILTER,"Remove Extraneous Sets","RemoveExtraneousSets",0,0,0,0,NULL,RemoveExtraneousSets,PROC_PRIORITY_DEFAULT, "Indexer")
101 
102 #define REGISTER_POPSET_WITHIN_GENBANK ObjMgrProcLoadEx (OMPROC_FILTER,"Add Popset Within GenBank Set","AddPopSetWithinGenBankSet",0,0,0,0,NULL,PopWithinGenBankSet,PROC_PRIORITY_DEFAULT, "Indexer")
103 
104 #define REGISTER_PHYSET_WITHIN_GENBANK ObjMgrProcLoadEx (OMPROC_FILTER,"Add Physet Within GenBank Set","AddPhySetWithinGenBankSet",0,0,0,0,NULL,PhyWithinGenBankSet,PROC_PRIORITY_DEFAULT, "Indexer")
105 
106 #define REGISTER_REMOVE_MESSEDUP ObjMgrProcLoadEx (OMPROC_FILTER,"Repair Messed Up Sets","RepairMessedUpSets",0,0,0,0,NULL,RepairMessedUpRecord,PROC_PRIORITY_DEFAULT, "Indexer")
107 
108 #define REGISTER_UPDATE_SEQALIGN ObjMgrProcLoadEx (OMPROC_FILTER, "Update SeqAlign","UpdateSeqAlign",OBJ_SEQALIGN,0,OBJ_SEQALIGN,0,NULL,NewUpdateSeqAlign,PROC_PRIORITY_DEFAULT, "Alignment")
109 
110 #define REGISTER_FIX_ALIGNMENT_OVER_GAPS ObjMgrProcLoadEx (OMPROC_FILTER, "Fix Alignment Over Gaps", "FixAlignmentOverGaps", 0,0,0,0,NULL,FixAlignmentOverGaps,PROC_PRIORITY_DEFAULT, "Alignment")
111 
112 #define REGISTER_FIX_ALIGNMENT_GAP_GAPS ObjMgrProcLoadEx (OMPROC_FILTER, "Fix Alignment Gaps Containing Known Gaps", "FixKnownGapAlignmentGaps", 0,0,0,0,NULL,ConsolidateGapGaps, PROC_PRIORITY_DEFAULT, "Alignment")
113 
114 #define REGISTER_REORDER_BY_ID ObjMgrProcLoadEx (OMPROC_FILTER, "Reorder by ID","ReorderByID",0,0,0,0,NULL,ReorderSetByAccession,PROC_PRIORITY_DEFAULT, "Indexer")
115 
116 #define REGISTER_MAKESEQALIGNNEWBLAST ObjMgrProcLoadEx (OMPROC_FILTER,"Make SeqAlign","CreateSeqAlign",0,0,0,0,NULL,GenerateSeqAlignFromSeqEntryUseNewBlast,PROC_PRIORITY_DEFAULT, "Alignment")
117 
118 #define REGISTER_MAKESEQALIGNMASTERNEWBLAST ObjMgrProcLoadEx (OMPROC_FILTER,"Make SeqAlign Choose Master","CreateSeqAlignChooseMaster",0,0,0,0,NULL,GenerateSeqAlignFromSeqEntryChooseMasterUseNewBlast,PROC_PRIORITY_DEFAULT, "Alignment")
119 
120 #define REGISTER_MAKESEQALIGNPNEWBLAST ObjMgrProcLoadEx (OMPROC_FILTER,"Make Protein SeqAlign","CreateSeqAlignProt",0,0,0,0,NULL,GenerateSeqAlignFromSeqEntryProtUseNewBlast,PROC_PRIORITY_DEFAULT, "Alignment")
121 
122 #define REGISTER_NORMSEQALIGN ObjMgrProcLoadEx (OMPROC_FILTER,"Validate SeqAlign","ValidateSeqAlign",0,0,0,0,NULL,ValidateSeqAlignFromData,PROC_PRIORITY_DEFAULT, "Alignment")
123 
124 #define REGISTER_NOMORESEGGAP ObjMgrProcLoadEx (OMPROC_FILTER,"Get Rid of Seg Gap","GetRidOfSegGap",0,0,0,0,NULL,NoMoreSegGap,PROC_PRIORITY_DEFAULT, "Alignment")
125 
126 #define REGISTER_GROUP_EXPLODE ObjMgrProcLoadEx (OMPROC_FILTER, "Explode a group", "GroupExplode", OBJ_SEQFEAT, 0, OBJ_SEQFEAT, 0, NULL, GroupExplodeFunc, PROC_PRIORITY_DEFAULT, "Indexer")
127 
128 #define REGISTER_INTERVAL_COMBINE ObjMgrProcLoadEx (OMPROC_FILTER, "Combine feature intervals", "IntervalCombine", OBJ_SEQFEAT, 0, OBJ_SEQFEAT, 0, NULL, IntervalCombineFunc, PROC_PRIORITY_DEFAULT, "Indexer")
129 
130 #define REGISTER_INTERVAL_COMBINE_AND_FUSE ObjMgrProcLoadEx (OMPROC_FILTER, "Combine and fuse feature intervals", "IntervalCombineAndFuse", OBJ_SEQFEAT, 0, OBJ_SEQFEAT, 0, NULL, IntervalCombineAndFuseFunc, PROC_PRIORITY_DEFAULT, "Indexer")
131 
132 #define REGISTER_BIOSEQ_REVCOMP_WITHFEAT ObjMgrProcLoadEx (OMPROC_FILTER, "Bioseq and Features RevComp", "BioseqFeatsRevComp", OBJ_BIOSEQ, 0, OBJ_BIOSEQ, 0, NULL, RevCompFuncFeat, PROC_PRIORITY_DEFAULT, "Utilities")
133 #define REGISTER_BIOSEQ_REVCOMP_NOTFEAT ObjMgrProcLoadEx (OMPROC_FILTER, "Bioseq only RevComp", "BioseqOnlyRevComp", OBJ_BIOSEQ, 0, OBJ_BIOSEQ, 0, NULL, RevCompFunc, PROC_PRIORITY_DEFAULT, "Utilities")
134 #define REGISTER_BIOSEQ_REVERSE ObjMgrProcLoadEx (OMPROC_FILTER, "Bioseq Reverse", "BioseqReverse", OBJ_BIOSEQ, 0, OBJ_BIOSEQ, 0, NULL, RevFunc, PROC_PRIORITY_DEFAULT, "Utilities")
135 #define REGISTER_BIOSEQ_COMPLEMENT ObjMgrProcLoadEx (OMPROC_FILTER, "Bioseq Complement", "BioseqComplement", OBJ_BIOSEQ, 0, OBJ_BIOSEQ, 0, NULL, CompFunc, PROC_PRIORITY_DEFAULT, "Utilities")
136 #define REGISTER_BIOSEQ_REVCOMP_BYID ObjMgrProcLoadEx (OMPROC_FILTER, "Bioseq and Features RevComp By ID", "RevCompByID", OBJ_BIOSEQ, 0, OBJ_BIOSEQ, 0, NULL, BioseqRevCompByID, PROC_PRIORITY_DEFAULT, "Utilities")
137 #define REGISTER_BIOSEQ_ORF ObjMgrProcLoadEx (OMPROC_FILTER, "ORF Finder", "OrfFinder", OBJ_BIOSEQ, 0, OBJ_BIOSEQ, 0, NULL, OrfFindFunc, PROC_PRIORITY_DEFAULT, "Utilities")
138 
139 #define REGISTER_BSP_INDEX ObjMgrProcLoadEx (OMPROC_FILTER,"Bioseq Index","MakeBioseqIndex",0,0,0,0,NULL,DoBioseqIndexing,PROC_PRIORITY_DEFAULT, "Indexer")
140 
141 #define REGISTER_FIND_NON_ACGT ObjMgrProcLoadEx (OMPROC_FILTER,"Find Non ACGT","FindNonACGT",0,0,0,0,NULL,FindNonACGT,PROC_PRIORITY_DEFAULT, "Indexer")
142 
143 #define REGISTER_OPENALED ObjMgrProcLoadEx (OMPROC_FILTER,"Open Align Editor 1","Open Contiguous Protein Alignment", 0,0,0,0,NULL,LaunchAlignEditorFromDesktop, PROC_PRIORITY_DEFAULT, "Alignment")
144 
145 #define REGISTER_OPENALED2 ObjMgrProcLoadEx (OMPROC_FILTER,"Open Align Editor 2","Open Interleave Protein Alignment", 0,0,0,0,NULL,LaunchAlignEditorFromDesktop2, PROC_PRIORITY_DEFAULT, "Alignment")
146 
147 #define REGISTER_DETACH ObjMgrProcLoadEx (OMPROC_FILTER,"Detach After Bioseq","DetachBioseq",OBJ_SEQFEAT,0,OBJ_SEQFEAT,0,NULL,DetachBioseq,PROC_PRIORITY_DEFAULT, "Misc")
148 
149 #define REGISTER_DESKTOP_REPORT ObjMgrProcLoadEx (OMPROC_FILTER, "Desktop Report", "DesktopReport", 0, 0, 0, 0, NULL, DesktopReportFunc, PROC_PRIORITY_DEFAULT, "Indexer")
150 
151 #define REGISTER_DESCRIPTOR_PROPAGATE ObjMgrProcLoadEx (OMPROC_FILTER, "Descriptor Propagate", "DescriptorPropagate", 0, 0, 0, 0, NULL, DescriptorPropagate, PROC_PRIORITY_DEFAULT, "Indexer")
152 
153 #define REGISTER_COPY_MASTER_SOURCE_TO_SEGMENTS ObjMgrProcLoadEx (OMPROC_FILTER, "Copy Master Source To Segments", "CopyMasterSourceToSegments", 0, 0, 0, 0, NULL, CopyMasterSourceToSegments, PROC_PRIORITY_DEFAULT, "Indexer")
154 
155 #define REGISTER_CLEAR_SEQENTRYSCOPE ObjMgrProcLoadEx (OMPROC_FILTER, "Clear SeqEntry Scope", "ClearSeqEntryScope", 0, 0, 0, 0, NULL, DoClearSeqEntryScope, PROC_PRIORITY_DEFAULT, "Indexer")
156 
157 #define REGISTER_REFGENEUSER_DESC_EDIT ObjMgrProcLoad(OMPROC_EDIT,"Edit RefGene UserTrack Desc","RefGene Tracking",OBJ_SEQDESC,Seq_descr_user,OBJ_SEQDESC,Seq_descr_user,NULL,RefGeneUserGenFunc,PROC_PRIORITY_DEFAULT)
158 extern Int2 LIBCALLBACK RefGeneUserGenFunc (Pointer data);
159 
160 #define REGISTER_GENOMEPROJSDBUSER_DESC_EDIT ObjMgrProcLoad(OMPROC_EDIT,"Edit GenomeProjectsDB User Desc","GenomeProjectsDB",OBJ_SEQDESC,Seq_descr_user,OBJ_SEQDESC,Seq_descr_user,NULL,GenomeProjectsDBUserGenFunc,PROC_PRIORITY_DEFAULT)
161 extern Int2 LIBCALLBACK GenomeProjectsDBUserGenFunc (Pointer data);
162 
163 #define REGISTER_DBLINKUSER_DESC_EDIT ObjMgrProcLoad(OMPROC_EDIT,"Edit DBLink User Desc","DBLink",OBJ_SEQDESC,Seq_descr_user,OBJ_SEQDESC,Seq_descr_user,NULL,DBlinkUserGenFunc,PROC_PRIORITY_DEFAULT)
164 extern Int2 LIBCALLBACK DBlinkUserGenFunc (Pointer data);
165 
166 #define REGISTER_TPAASSEMBLYUSER_DESC_EDIT ObjMgrProcLoad(OMPROC_EDIT,"Edit Assembly User Desc","TPA Assembly",OBJ_SEQDESC,Seq_descr_user,OBJ_SEQDESC,Seq_descr_user,NULL,AssemblyUserGenFunc,PROC_PRIORITY_DEFAULT)
167 extern Int2 LIBCALLBACK AssemblyUserGenFunc (Pointer data);
168 
169 #define REGISTER_STRUCTUREDCOMMENTUSER_DESC_EDIT ObjMgrProcLoad(OMPROC_EDIT,"Edit StructuredComment User Desc","Structured Comment",OBJ_SEQDESC,Seq_descr_user,OBJ_SEQDESC,Seq_descr_user,NULL,StruCommUserGenFunc,PROC_PRIORITY_DEFAULT)
170 extern Int2 LIBCALLBACK StruCommUserGenFunc (Pointer data);
171 
172 #define REGISTER_UNVERIFIED_DESC_EDIT ObjMgrProcLoad(OMPROC_EDIT,"Edit Unverified User Desc","Unverified",OBJ_SEQDESC,Seq_descr_user,OBJ_SEQDESC,Seq_descr_user,NULL,UnverifiedUserGenFunc,PROC_PRIORITY_DEFAULT)
173 extern Int2 LIBCALLBACK UnverifiedUserGenFunc (Pointer data);
174 
175 #define REGISTER_AUTHORIZEDACCESSUSER_DESC_EDIT ObjMgrProcLoad(OMPROC_EDIT,"Edit AuthorizedAccess User Desc","AuthorizedAccess",OBJ_SEQDESC,Seq_descr_user,OBJ_SEQDESC,Seq_descr_user,NULL,AuthorizedAccessUserGenFunc,PROC_PRIORITY_DEFAULT)
176 extern Int2 LIBCALLBACK AuthorizedAccessUserGenFunc (Pointer data);
177 
178 #define REGISTER_FEAT_INTERVALS_TO_DELTA ObjMgrProcLoadEx (OMPROC_FILTER, "Feature Intervals to Delta Sequence", "FeatToDelta", 0,0,0,0,NULL, FeatToDeltaSeq, PROC_PRIORITY_DEFAULT, "Indexer")
179 
180 #if defined(OS_UNIX) || defined(OS_MSWIN)
181 #define REGISTER_CORRECTRNASTRANDSMART ObjMgrProcLoadEx (OMPROC_FILTER, "Correct RNA Strand Use SMART BLAST Results","CorrectRNAStrandSMART",0,0,0,0,NULL,CorrectRNAStrandednessUseSmart,PROC_PRIORITY_DEFAULT, "Indexer")
182 #define REGISTER_CORRECTRNASTRAND ObjMgrProcLoadEx (OMPROC_FILTER, "Correct RNA Strand Use Local Database Search","CorrectRNAStrandLocalDatabase",0,0,0,0,NULL,CorrectRNAStrandedness,PROC_PRIORITY_DEFAULT, "Indexer")
183 #endif
184 
185 
186 /* commands for Desktop Segregate menu */
187 #define REGISTER_SEGREGATE_BY_FIELD ObjMgrProcLoadEx (OMPROC_FILTER, "Segregate By Options","Segregate",0,0,0,0,NULL,SegregateSetsByField,PROC_PRIORITY_DEFAULT, "Segregate")
188 
189 #define REGISTER_SEQUESTER_SETS ObjMgrProcLoadEx (OMPROC_FILTER, "Sequester", "Sequester",0,0,0,0,NULL,SequesterSequences, PROC_PRIORITY_DEFAULT, "Sequester")
190 /* commands for Desktop SegmentedSets menu */
191 #define REGISTER_CREATESEGSET ObjMgrProcLoadEx (OMPROC_FILTER,"Create Segmented Set", "CreateSegSet", 0,0,0,0,NULL,CreateSegSet, PROC_PRIORITY_DEFAULT, "SegmentedSets")
192 #define REGISTER_UPDATESEGSET ObjMgrProcLoadEx (OMPROC_FILTER,"Update Segmented Set","UpdateSegSet",0,0,0,0,NULL,UpdateSegSet,PROC_PRIORITY_DEFAULT, "SegmentedSets")
193 #define REGISTER_NEWUPDATESEGSET ObjMgrProcLoadEx (OMPROC_FILTER,"New Update Segmented Set","NewUpdateSegSet",0,0,0,0,NULL,NewUpdateSegSet,PROC_PRIORITY_DEFAULT, "SegmentedSets")
194 #define REGISTER_ADJUSTMULTISEGSEQ ObjMgrProcLoadEx (OMPROC_FILTER,"Adjust SegSeq Length","AdjustSegLength",0,0,0,0,NULL,AdjustSegSeqLength,PROC_PRIORITY_DEFAULT, "SegmentedSets")
195 #define REGISTER_UNDOSEGSET ObjMgrProcLoadEx (OMPROC_FILTER,"Undo Segmented Set","UndoSegSet",0,0,0,0,NULL,UndoSegSet,PROC_PRIORITY_DEFAULT, "SegmentedSets")
196 #define REGISTER_SEGSETREMOVESETSINSET ObjMgrProcLoadEx (OMPROC_FILTER,"Remove Sets in Selected Set (Like Undo SegSet)","RemoveSetsInSelectedSet",0,0,0,0,NULL,RemoveSetsInSelectedSet,PROC_PRIORITY_DEFAULT, "SegmentedSets")
197 
198 
199 typedef struct _explodeStruct {
200   SeqEntryPtr topSep;
201   SeqFeatPtr  seqFeatPtr;
202   struct _explodeStruct PNTR next;
203 } ExplodeStruct, PNTR ExplodeStructPtr;
204 
205 typedef struct {
206   DESCRIPTOR_FORM_BLOCK
207   PopuP        fromPopup;
208   PopuP        toPopup;
209   Int2         fromStrand;
210   Int2         toStrand;
211   ValNodePtr   featlist;
212   LisT         feature;
213   Int2         featSubType;
214   CharPtr      findThisStr;
215   TexT         findThis;
216   Boolean      case_insensitive;
217   ButtoN       case_insensitive_btn;
218   Boolean      when_string_not_present;
219   ButtoN       when_string_not_present_btn;
220 } EditStrand, PNTR EditStrandPtr;
221 
AddBspToSegSet(BioseqPtr segseq,BioseqPtr bsp)222 static void AddBspToSegSet (BioseqPtr segseq, BioseqPtr bsp)
223 
224 {
225   SeqIdPtr   sip;
226   SeqLocPtr  slp;
227 
228   if (segseq == NULL) return;
229   slp = ValNodeNew ((ValNodePtr) segseq->seq_ext);
230   if (slp == NULL) return;
231   if (segseq->seq_ext == NULL) {
232     segseq->seq_ext = (Pointer) slp;
233   }
234   if (bsp != NULL && bsp->length > 0) {
235     segseq->length += bsp->length;
236     slp->choice = SEQLOC_WHOLE;
237     sip = SeqIdFindBest (bsp->id, 0);
238     slp->data.ptrvalue = (Pointer) SeqIdStripLocus (SeqIdDup (sip));
239   } else {
240     slp->choice = SEQLOC_NULL;
241   }
242 }
243 
RemoveMolInfoDescriptors(SeqEntryPtr sep,Pointer mydata,Int4 index,Int2 indent)244 static void RemoveMolInfoDescriptors (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
245 
246 {
247   BioseqPtr      bsp;
248   BioseqSetPtr   bssp;
249   ValNodePtr     nextsdp;
250   Pointer PNTR   prevsdp;
251   ValNodePtr     sdp;
252 
253   if (IS_Bioseq (sep)) {
254     bsp = (BioseqPtr) sep->data.ptrvalue;
255     sdp = bsp->descr;
256     prevsdp = (Pointer PNTR) &(bsp->descr);
257   } else if (IS_Bioseq_set (sep)) {
258     bssp = (BioseqSetPtr) sep->data.ptrvalue;
259     sdp = bssp->descr;
260     prevsdp = (Pointer PNTR) &(bssp->descr);
261   } else return;
262   while (sdp != NULL) {
263     nextsdp = sdp->next;
264     if (sdp->choice == Seq_descr_molinfo) {
265       *(prevsdp) = sdp->next;
266       sdp->next = NULL;
267       SeqDescFree (sdp);
268     } else {
269       prevsdp = (Pointer PNTR) &(sdp->next);
270     }
271     sdp = nextsdp;
272   }
273 }
274 
MoveSegSetMolInfo(BioseqPtr segseq,BioseqSetPtr parts,BioseqSetPtr segset)275 static void MoveSegSetMolInfo (BioseqPtr segseq, BioseqSetPtr parts, BioseqSetPtr segset)
276 
277 {
278   MolInfoPtr   first;
279   MolInfoPtr   mip;
280   SeqEntryPtr  partssep;
281   ValNodePtr   sdp;
282   SeqEntryPtr  sep;
283   SeqEntryPtr  tmp;
284 
285   if (segseq == NULL || parts == NULL || parts->seq_set == NULL || segset == NULL) return;
286   sep = SeqMgrGetSeqEntryForData (segset);
287   if (sep == NULL) return;
288   sdp = SeqEntryGetSeqDescr (sep, Seq_descr_molinfo, NULL);
289   if (sdp != NULL) return;
290   first = NULL;
291   partssep = SeqMgrGetSeqEntryForData (parts);
292   if (partssep != NULL) {
293     sdp = SeqEntryGetSeqDescr (partssep, Seq_descr_molinfo, NULL);
294     if (sdp != NULL) {
295       first = (MolInfoPtr) sdp->data.ptrvalue;
296     }
297   }
298   for (tmp = parts->seq_set; tmp != NULL; tmp = tmp->next) {
299     sdp = SeqEntryGetSeqDescr (tmp, Seq_descr_molinfo, NULL);
300     if (sdp != NULL) {
301       if (first == NULL) {
302         first = (MolInfoPtr) sdp->data.ptrvalue;
303       } else {
304         mip = (MolInfoPtr) sdp->data.ptrvalue;
305         if (first != NULL && mip != NULL) {
306           if (mip->biomol != first->biomol) return;
307         }
308       }
309     }
310   }
311   if (first == NULL) return;
312   mip = MolInfoNew ();
313   if (mip == NULL) return;
314   sdp = CreateNewDescriptor (sep, Seq_descr_molinfo);
315   if (sdp == NULL) return;
316   sdp->data.ptrvalue = (Pointer) mip;
317   mip->biomol = first->biomol;
318   mip->tech = first->tech;
319   mip->completeness = first->completeness;
320   mip->techexp = StringSaveNoNull (first->techexp);
321   if (partssep != NULL) {
322     SeqEntryExplore (partssep, NULL, RemoveMolInfoDescriptors);
323   }
324   for (tmp = parts->seq_set; tmp != NULL; tmp = tmp->next) {
325     SeqEntryExplore (tmp, NULL, RemoveMolInfoDescriptors);
326   }
327 }
328 
329 
DoDescriptorsMatch(SeqDescrPtr sdp1,SeqDescrPtr sdp2)330 static Boolean DoDescriptorsMatch (SeqDescrPtr sdp1, SeqDescrPtr sdp2)
331 {
332   if (sdp1 == NULL || sdp2 == NULL || sdp1->choice != sdp2->choice)
333   {
334     return FALSE;
335   }
336 
337   /* compare publications */
338   if (sdp1->choice == Seq_descr_pub
339       && PubdescContentMatch (sdp1->data.ptrvalue, sdp2->data.ptrvalue))
340   {
341     return TRUE;
342   }
343   /* compare sources */
344   else if (sdp1->choice == Seq_descr_source
345       && BioSourceMatch (sdp1->data.ptrvalue, sdp2->data.ptrvalue))
346   {
347     return TRUE;
348   }
349   /* compare update dates */
350   else if (sdp1->choice == Seq_descr_update_date
351       && DateMatch (sdp1->data.ptrvalue, sdp2->data.ptrvalue, TRUE))
352   {
353     return TRUE;
354   }
355   else
356   {
357     return FALSE;
358   }
359 }
360 
FindIdenticalDescriptorInEachBioseqInList(SeqDescrPtr sdp,SeqEntryPtr sep)361 static Boolean FindIdenticalDescriptorInEachBioseqInList (SeqDescrPtr sdp, SeqEntryPtr sep)
362 {
363   SeqDescrPtr check_sdp;
364   Boolean     found_match = FALSE;
365   BioseqPtr   bsp;
366 
367   if (sdp == NULL)
368   {
369     return FALSE;
370   }
371   if (sep == NULL)
372   {
373     return TRUE;
374   }
375 
376   if (!IS_Bioseq(sep) || sep->data.ptrvalue == NULL)
377   {
378     return FALSE;
379   }
380 
381   bsp = (BioseqPtr) sep->data.ptrvalue;
382   check_sdp = bsp->descr;
383   while (check_sdp != NULL && !found_match)
384   {
385     found_match = DoDescriptorsMatch (check_sdp, sdp);
386     check_sdp = check_sdp->next;
387   }
388 
389   if (found_match)
390   {
391     found_match = FindIdenticalDescriptorInEachBioseqInList (sdp, sep->next);
392   }
393 
394   return found_match;
395 }
396 
397 
RemoveIdenticalDescriptorInEachBioseqInList(SeqDescrPtr sdp,SeqEntryPtr sep)398 static void RemoveIdenticalDescriptorInEachBioseqInList (SeqDescrPtr sdp, SeqEntryPtr sep)
399 {
400   SeqDescrPtr check_sdp, prev = NULL;
401   BioseqPtr   bsp;
402 
403   if (sdp == NULL || sep == NULL || !IS_Bioseq(sep) || sep->data.ptrvalue == NULL)
404   {
405     return;
406   }
407 
408   bsp = (BioseqPtr) sep->data.ptrvalue;
409   check_sdp = bsp->descr;
410   while (check_sdp != NULL)
411   {
412     if (DoDescriptorsMatch (check_sdp, sdp))
413     {
414       if (prev == NULL)
415       {
416         bsp->descr = check_sdp->next;
417       }
418       else
419       {
420         prev->next = check_sdp->next;
421       }
422       check_sdp->next = NULL;
423       check_sdp = SeqDescrFree (check_sdp);
424     }
425     else
426     {
427       prev = check_sdp;
428       check_sdp = check_sdp->next;
429     }
430   }
431 
432   RemoveIdenticalDescriptorInEachBioseqInList (sdp, sep->next);
433 }
434 
435 
436 static void
MoveUpIdenticalSegSetDescriptors(BioseqPtr segseq,BioseqSetPtr parts,BioseqSetPtr segset,Int2 descriptor_choice)437 MoveUpIdenticalSegSetDescriptors
438 (BioseqPtr    segseq,
439  BioseqSetPtr parts,
440  BioseqSetPtr segset,
441  Int2         descriptor_choice)
442 {
443   SeqEntryPtr  sep;
444   BioseqPtr    bsp;
445   BioseqSetPtr bssp;
446   SeqDescrPtr  sdp, sdp_next, prev = NULL;
447   SeqDescrPtr  moved_list = NULL;
448 
449   if (segseq == NULL || parts == NULL || parts->seq_set == NULL || segset == NULL
450       || ! IS_Bioseq (parts->seq_set) || parts->seq_set->data.ptrvalue == NULL)
451   {
452     return;
453   }
454 
455   sep = GetBestTopParentForData (segseq->idx.entityID, segseq);
456   if (sep == NULL)
457   {
458     sep = SeqMgrGetSeqEntryForData (segset);
459   }
460 
461   bsp = (BioseqPtr) parts->seq_set->data.ptrvalue;
462 
463   sdp = bsp->descr;
464   while (sdp != NULL)
465   {
466     sdp_next = sdp->next;
467     if (sdp->choice == descriptor_choice
468         && FindIdenticalDescriptorInEachBioseqInList (sdp, parts->seq_set->next))
469     {
470       RemoveIdenticalDescriptorInEachBioseqInList (sdp, parts->seq_set->next);
471       if (prev == NULL)
472       {
473         bsp->descr = sdp->next;
474       }
475       else
476       {
477         prev->next = sdp->next;
478       }
479       sdp->next = NULL;
480       ValNodeLink (&moved_list, sdp);
481     }
482     else
483     {
484       prev = sdp;
485     }
486     sdp = sdp_next;
487   }
488 
489   if (IS_Bioseq_set (sep))
490   {
491     bssp = (BioseqSetPtr) sep->data.ptrvalue;
492     ValNodeLink (&(bssp->descr), moved_list);
493   }
494   else if (IS_Bioseq (sep))
495   {
496     bsp = (BioseqPtr) sep->data.ptrvalue;
497     ValNodeLink (&(bsp->descr), moved_list);
498   }
499 }
500 
501 
DoUpdateSegSet(BioseqPtr segseq,BioseqSetPtr parts,Boolean ask,Boolean force_intersperse)502 static void DoUpdateSegSet (BioseqPtr segseq, BioseqSetPtr parts, Boolean ask, Boolean force_intersperse)
503 
504 {
505   MsgAnswer    ans;
506   BioseqPtr    bsp;
507   Boolean      notFirst;
508   Boolean      nullsBetween;
509   SeqFeatPtr   sfp;
510   SeqFeatPtr   sfpnext;
511   SeqLocPtr    slp;
512   SeqEntryPtr  tmp;
513 
514   if (segseq == NULL || parts == NULL || parts->seq_set == NULL) return;
515   tmp = parts->seq_set;
516   notFirst = FALSE;
517   nullsBetween = FALSE;
518   segseq->length = 0;
519   switch (segseq->seq_ext_type) {
520     case 1:    /* seg-ext */
521       slp = (ValNodePtr) segseq->seq_ext;
522       while (slp != NULL) {
523         if (slp->choice == SEQLOC_NULL) {
524           nullsBetween = TRUE;
525         }
526         slp = slp->next;
527       }
528       SeqLocSetFree ((ValNodePtr) segseq->seq_ext);
529       break;
530     case 2:   /* reference */
531       SeqLocFree ((ValNodePtr) segseq->seq_ext);
532       break;
533     case 3:   /* map */
534       sfp = (SeqFeatPtr) segseq->seq_ext;
535       while (sfp != NULL) {
536         sfpnext = sfp->next;
537         SeqFeatFree (sfp);
538         sfp = sfpnext;
539       }
540       break;
541     default:
542       break;
543   }
544   segseq->seq_ext = NULL;
545   if (ask) {
546     if (nullsBetween) {
547       ans = Message (MSG_YN, "Intersperse intervals with gaps (currently has gaps)?");
548     } else {
549       ans = Message (MSG_YN, "Intersperse intervals with gaps (currently no gaps)?");
550     }
551     nullsBetween = (Boolean) (ans == ANS_YES);
552   }
553   else
554   {
555     nullsBetween |= force_intersperse;
556   }
557   while (tmp != NULL) {
558     if (nullsBetween && notFirst) {
559       AddBspToSegSet (segseq, NULL);
560     }
561     bsp = (BioseqPtr) tmp->data.ptrvalue;
562     if (bsp != NULL) {
563       AddBspToSegSet (segseq, bsp);
564     }
565     notFirst = TRUE;
566     tmp = tmp->next;
567   }
568 }
569 
570 typedef struct updatesegstruc {
571   BioseqSetPtr      parts;
572   BioseqPtr         segseq;
573   BioseqSetPtr      segset;
574 } UpdateSegStruc, PNTR UpdateSegStrucPtr;
575 
FindSegSetComponentsCallback(SeqEntryPtr sep,Pointer mydata,Int4 index,Int2 indent)576 static void FindSegSetComponentsCallback (SeqEntryPtr sep, Pointer mydata,
577                                           Int4 index, Int2 indent)
578 
579 {
580   BioseqPtr          bsp;
581   BioseqSetPtr       bssp;
582   UpdateSegStrucPtr  ussp;
583 
584   if (sep != NULL && sep->data.ptrvalue && mydata != NULL) {
585     ussp = (UpdateSegStrucPtr) mydata;
586     if (sep->choice == 1) {
587       bsp = (BioseqPtr) sep->data.ptrvalue;
588       if (bsp->repr == Seq_repr_seg) {
589         ussp->segseq = bsp;
590       }
591     } else if (sep->choice == 2) {
592       bssp = (BioseqSetPtr) sep->data.ptrvalue;
593       if (bssp->_class == 2) {
594         ussp->segset = bssp;
595       } else if (bssp->_class == 4) {
596         ussp->parts = bssp;
597       }
598     }
599   }
600 }
601 
UpdateSegList(SeqEntryPtr sep,Pointer mydata,SeqEntryFunc mycallback,Int4 index,Int2 indent)602 static Int4 UpdateSegList (SeqEntryPtr sep, Pointer mydata,
603                            SeqEntryFunc mycallback,
604                            Int4 index, Int2 indent)
605 
606 {
607   BioseqSetPtr  bssp;
608 
609   if (sep == NULL) return index;
610   if (mycallback != NULL)
611     (*mycallback) (sep, mydata, index, indent);
612   index++;
613   if (IS_Bioseq (sep)) return index;
614   if (Bioseq_set_class (sep) == 4) return index;
615   bssp = (BioseqSetPtr) sep->data.ptrvalue;
616   sep = bssp->seq_set;
617   indent++;
618   while (sep != NULL) {
619     index = UpdateSegList (sep, mydata, mycallback, index, indent);
620     sep = sep->next;
621   }
622   return index;
623 }
624 
625 #define UpdateSegExplore(a,b,c) UpdateSegList(a, b, c, 0L, 0);
626 
627 extern Int2 DoOneSegFixup (SeqEntryPtr sep, Boolean ask);
DoOneSegFixup(SeqEntryPtr sep,Boolean ask)628 extern Int2 DoOneSegFixup (SeqEntryPtr sep, Boolean ask)
629 
630 {
631   BioseqSetPtr    bssp;
632   Uint1           choice;
633   Int2            count;
634   SeqEntryPtr     insert;
635   SeqEntryPtr     next;
636   ObjMgrDataPtr   omdptop;
637   ObjMgrData      omdata;
638   Uint2           parenttype;
639   Pointer         parentptr;
640   UpdateSegStruc  uss;
641   SeqEntryPtr     tmp;
642 
643   if (sep == NULL) return 0;
644   if (IS_Bioseq_set (sep)) {
645     bssp = (BioseqSetPtr) sep->data.ptrvalue;
646     if (bssp != NULL && (bssp->_class == BioseqseqSet_class_genbank
647                          || IsPopPhyEtcSet (bssp->_class))) {
648       choice = 0;
649       for (tmp = bssp->seq_set; tmp != NULL; tmp = tmp->next) {
650         if (choice == 0) {
651           choice = tmp->choice;
652         } else if (choice != tmp->choice) {
653           return 0;
654         }
655       }
656       count = 0;
657       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
658         count += DoOneSegFixup (sep, ask);
659       }
660       return count;
661     }
662   }
663   if (IS_Bioseq (sep) && sep->next != NULL) {
664     count = 0;
665     SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
666     GetSeqEntryParent (sep, &parentptr, &parenttype);
667     insert = sep->next;
668     sep->next = NULL;
669     while (insert != NULL) {
670       next = insert->next;
671       insert->next = NULL;
672       AddSeqEntryToSeqEntry (sep, insert, FALSE);
673       count++;
674       insert = next;
675     }
676     SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
677     RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
678     uss.segseq = NULL;
679     uss.parts = NULL;
680     uss.segset = NULL;
681     UpdateSegExplore (sep, (Pointer) &uss, FindSegSetComponentsCallback);
682     if (uss.segseq != NULL && uss.parts != NULL && uss.segset != NULL) {
683       DoUpdateSegSet (uss.segseq, uss.parts, ask, FALSE);
684       MoveSegSetMolInfo (uss.segseq, uss.parts, uss.segset);
685 
686       MoveUpIdenticalSegSetDescriptors (uss.segseq, uss.parts, uss.segset, Seq_descr_pub);
687       MoveUpIdenticalSegSetDescriptors (uss.segseq, uss.parts, uss.segset, Seq_descr_update_date);
688       MoveUpIdenticalSegSetDescriptors (uss.segseq, uss.parts, uss.segset, Seq_descr_source);
689     }
690     return count;
691   }
692   uss.segseq = NULL;
693   uss.parts = NULL;
694   uss.segset = NULL;
695   UpdateSegExplore (sep, (Pointer) &uss, FindSegSetComponentsCallback);
696   if (uss.segseq != NULL && uss.parts != NULL && uss.segset != NULL) {
697     DoUpdateSegSet (uss.segseq, uss.parts, ask, FALSE);
698     MoveSegSetMolInfo (uss.segseq, uss.parts, uss.segset);
699 
700     MoveUpIdenticalSegSetDescriptors (uss.segseq, uss.parts, uss.segset, Seq_descr_pub);
701     MoveUpIdenticalSegSetDescriptors (uss.segseq, uss.parts, uss.segset, Seq_descr_update_date);
702     MoveUpIdenticalSegSetDescriptors (uss.segseq, uss.parts, uss.segset, Seq_descr_source);
703     return 1;
704   }
705   return 0;
706 }
707 
708 static void
MoveNucProtSetFeaturesAndDescriptorsToNucSeg(BioseqSetPtr bssp,BioseqPtr bsp)709 MoveNucProtSetFeaturesAndDescriptorsToNucSeg
710 (BioseqSetPtr bssp, BioseqPtr bsp)
711 {
712   SeqAnnotPtr last_sap;
713   SeqDescrPtr last_sdp;
714   if (bssp == NULL || bsp == NULL)
715   {
716     return;
717   }
718   last_sap = bsp->annot;
719   while (last_sap != NULL && last_sap->next != NULL)
720   {
721     last_sap = last_sap->next;
722   }
723   if (last_sap == NULL)
724   {
725     bsp->annot = bssp->annot;
726   }
727   else
728   {
729     last_sap->next = bssp->annot;
730   }
731   bssp->annot = NULL;
732 
733   last_sdp = bsp->descr;
734   while (last_sdp != NULL && last_sdp->next != NULL)
735   {
736     last_sdp = last_sdp->next;
737   }
738   if (last_sdp == NULL)
739   {
740     bsp->descr = bssp->descr;
741   }
742   else
743   {
744     last_sdp->next = bssp->descr;
745   }
746   bssp->descr = NULL;
747 }
748 
UpdateOneSegSet(BioseqSetPtr seg_bssp,Boolean intersperse_nulls)749 static void UpdateOneSegSet (BioseqSetPtr seg_bssp, Boolean intersperse_nulls)
750 {
751   BioseqPtr    seg = NULL;
752   BioseqSetPtr parts = NULL;
753   SeqEntryPtr  sep;
754   BioseqPtr    bsp;
755   BioseqSetPtr bssp;
756 
757   if (seg_bssp == NULL || seg_bssp->_class != BioseqseqSet_class_segset)
758   {
759     return;
760   }
761 
762   for (sep = seg_bssp->seq_set; sep != NULL; sep = sep->next)
763   {
764     if (IS_Bioseq (sep))
765     {
766       bsp = (BioseqPtr) sep->data.ptrvalue;
767       if (bsp != NULL
768           && ISA_na (bsp->mol)
769           && bsp->repr == Seq_repr_seg)
770       {
771         seg = bsp;
772       }
773     } else if (IS_Bioseq_set (sep)) {
774       bssp = (BioseqSetPtr) sep->data.ptrvalue;
775       if (bssp != NULL
776           && bssp->_class == BioseqseqSet_class_parts)
777       {
778         parts = bssp;
779       }
780     }
781   }
782   DoUpdateSegSet (seg, parts, FALSE, intersperse_nulls);
783   MoveSegSetMolInfo (seg, parts, seg_bssp);
784   MoveUpIdenticalSegSetDescriptors (seg, parts, seg_bssp, Seq_descr_pub);
785   MoveUpIdenticalSegSetDescriptors (seg, parts, seg_bssp, Seq_descr_update_date);
786   MoveUpIdenticalSegSetDescriptors (seg, parts, seg_bssp, Seq_descr_source);
787 }
788 
ConvertOneSetToSegSet(SeqEntryPtr sep,Boolean intersperse_nulls)789 static void ConvertOneSetToSegSet (SeqEntryPtr sep, Boolean intersperse_nulls)
790 {
791   BioseqSetPtr bssp, this_bssp;
792   BioseqPtr    seg;
793   SeqEntryPtr  this_sep, next_sep;
794   SeqEntryPtr  segment_list;
795   SeqEntryPtr  nuc_list = NULL, last_nuc = NULL;
796   SeqEntryPtr  prot_list = NULL, last_prot = NULL;
797   SeqEntryPtr  nps_next, nuc_seg;
798   SeqEntryPtr  nuc_sep, parts_sep, seg_sep;
799   BioseqSetPtr seg_bssp, parts;
800   BioseqPtr    bsp;
801   SeqLocPtr    slp;
802   ObjMgrDataPtr     omdptop;
803   ObjMgrData        omdata;
804   Uint2             parenttype;
805   Pointer           parentptr;
806   BioseqSetPtr      wrapper_bssp;
807   SeqEntryPtr       tmp_sep;
808 
809   if (sep == NULL || ! IS_Bioseq_set (sep))
810   {
811     return;
812   }
813   bssp = (BioseqSetPtr) sep->data.ptrvalue;
814   if (bssp == NULL
815       || bssp->_class == BioseqseqSet_class_nuc_prot
816       || bssp->_class == BioseqseqSet_class_segset)
817   {
818     return;
819   }
820 
821   SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
822   GetSeqEntryParent (sep, &parentptr, &parenttype);
823 
824 
825   segment_list = bssp->seq_set;
826   bssp->seq_set = NULL;
827 
828   for (this_sep = segment_list;
829        this_sep != NULL;
830        this_sep = next_sep)
831   {
832     next_sep = this_sep->next;
833     this_sep->next = NULL;
834     if (IS_Bioseq (this_sep))
835     {
836       if (nuc_list == NULL)
837       {
838         nuc_list = this_sep;
839       }
840       else
841       {
842         if (last_nuc == NULL)
843         {
844           last_nuc = nuc_list;
845         }
846         while (last_nuc->next != NULL)
847         {
848           last_nuc = last_nuc->next;
849         }
850         last_nuc->next = this_sep;
851       }
852     }
853     else if (IS_Bioseq_set (this_sep))
854     {
855       this_bssp = (BioseqSetPtr) this_sep->data.ptrvalue;
856       if (this_bssp != NULL
857           && this_bssp->_class == BioseqseqSet_class_nuc_prot
858           && this_bssp->seq_set != NULL)
859       {
860         nuc_seg = this_bssp->seq_set;
861         this_bssp->seq_set = NULL;
862         nps_next = nuc_seg->next;
863         nuc_seg->next = NULL;
864         /* move set features to segment */
865         bsp = (BioseqPtr) nuc_seg->data.ptrvalue;
866         MoveNucProtSetFeaturesAndDescriptorsToNucSeg (this_bssp, bsp);
867 
868         /* add nuc_seg to nuc_list */
869         if (nuc_list == NULL)
870         {
871           nuc_list = nuc_seg;
872         }
873         else
874         {
875           if (last_nuc == NULL)
876           {
877             last_nuc = nuc_list;
878           }
879           while (last_nuc->next != NULL)
880           {
881             last_nuc = last_nuc->next;
882           }
883           last_nuc->next = nuc_seg;
884         }
885 
886         /* add proteins to prot_list */
887         if (prot_list == NULL)
888         {
889           prot_list = nps_next;
890         }
891         else
892         {
893           /* add proteins to protein list */
894           if (last_prot == NULL)
895           {
896             last_prot = prot_list;
897           }
898           while (last_prot->next != NULL)
899           {
900             last_prot = last_prot->next;
901           }
902           last_prot->next = nps_next;
903         }
904       }
905 
906       /* remove nuc-prot set */
907       SeqEntryFree (this_sep);
908     }
909   }
910 
911   if (nuc_list == NULL)
912   {
913     return;
914   }
915 
916   /* create segment and parts from nuc_list */
917   bsp = nuc_list->data.ptrvalue;
918   seg = BioseqNew ();
919   if (seg == NULL) return;
920   seg->mol = bsp->mol;
921   seg->repr = Seq_repr_seg;
922   seg->seq_ext_type = 1;
923   seg->length = 0;
924   seg->id = MakeUniqueSeqID ("segseq_");
925   SeqMgrAddToBioseqIndex (seg);
926 
927   nuc_sep = SeqEntryNew ();
928   if (nuc_sep == NULL) return;
929   nuc_sep->choice = 1;
930   nuc_sep->data.ptrvalue = (Pointer) seg;
931 
932   parts = BioseqSetNew ();
933   if (parts == NULL) return;
934   parts->_class = 4;
935 
936   parts_sep = SeqEntryNew ();
937   if (parts_sep == NULL) return;
938   parts_sep->choice = 2;
939   parts_sep->data.ptrvalue = (Pointer) parts;
940   nuc_sep->next = parts_sep;
941 
942   parts->seq_set = nuc_list;
943   for (this_sep = nuc_list; this_sep != NULL; this_sep = this_sep->next)
944   {
945     bsp = (BioseqPtr) this_sep->data.ptrvalue;
946     if (bsp == NULL)
947     {
948       continue;
949     }
950     slp = ValNodeNew ((ValNodePtr) seg->seq_ext);
951     if (slp == NULL)
952     {
953       continue;
954     }
955 
956     if (seg->seq_ext == NULL)
957     {
958       seg->seq_ext = (Pointer) slp;
959     }
960     if (bsp->length >= 0)
961     {
962       seg->length += bsp->length;
963       slp->choice = SEQLOC_WHOLE;
964       slp->data.ptrvalue = (Pointer) SeqIdStripLocus (SeqIdDup (SeqIdFindBest (bsp->id, 0)));
965     } else {
966       slp->choice = SEQLOC_NULL;
967     }
968   }
969 
970   if (prot_list == NULL)
971   {
972     /* we just have nucleotides, so change the BioseqSet class to segset */
973     bssp->_class = BioseqseqSet_class_segset;
974     bssp->seq_set = nuc_sep;
975     seg_bssp = bssp;
976   }
977   else
978   {
979     /* change the BioseqSet class to nucprot, create the segmented
980      * set and put it in the nucleotide slot, and then add the proteins
981      */
982     bssp->_class = BioseqseqSet_class_nuc_prot;
983     seg_sep = SeqEntryNew ();
984     seg_bssp = BioseqSetNew ();
985     seg_sep->choice = 2;
986     seg_sep->data.ptrvalue = (Pointer) seg_bssp;
987     seg_bssp->_class = BioseqseqSet_class_segset;
988     seg_bssp->seq_set = nuc_sep;
989 
990     bssp->seq_set = seg_sep;
991     seg_sep->next = prot_list;
992   }
993 
994   /* if the set we have converted to a segset used to be our genbank wrapper,
995    * create a new genbank wrapper
996    */
997   if (parentptr == NULL)
998   {
999     tmp_sep = SeqEntryNew ();
1000     tmp_sep->choice = sep->choice;
1001     tmp_sep->data.ptrvalue = sep->data.ptrvalue;
1002     wrapper_bssp = BioseqSetNew ();
1003     wrapper_bssp->_class = BioseqseqSet_class_genbank;
1004     wrapper_bssp->seq_set = tmp_sep;
1005     sep->choice = 2;
1006     sep->data.ptrvalue = wrapper_bssp;
1007   }
1008 
1009   SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
1010   RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
1011 
1012   UpdateOneSegSet (seg_bssp, intersperse_nulls);
1013 }
1014 
IsFlatNucProtSet(BioseqSetPtr bssp)1015 static Boolean IsFlatNucProtSet (BioseqSetPtr bssp)
1016 {
1017   SeqEntryPtr this_sep;
1018 
1019   if (bssp == NULL || bssp->seq_set == NULL
1020       || bssp->_class != BioseqseqSet_class_nuc_prot)
1021   {
1022     return FALSE;
1023   }
1024 
1025   for (this_sep = bssp->seq_set; this_sep != NULL; this_sep = this_sep->next)
1026   {
1027     if (!IS_Bioseq (this_sep))
1028     {
1029       return FALSE;
1030     }
1031   }
1032   return TRUE;
1033 }
1034 
NewSegFixup(SeqEntryPtr sep,Boolean intersperse_nulls)1035 static void NewSegFixup (SeqEntryPtr sep, Boolean intersperse_nulls)
1036 {
1037   BioseqSetPtr bssp, this_bssp;
1038   SeqEntryPtr  this_sep;
1039   Boolean      can_convert = TRUE;
1040 
1041   if (sep == NULL || IS_Bioseq (sep))
1042   {
1043     return;
1044   }
1045 
1046   bssp = (BioseqSetPtr) sep->data.ptrvalue;
1047   if (bssp == NULL)
1048   {
1049     return;
1050   }
1051   else if (bssp->_class == BioseqseqSet_class_segset)
1052   {
1053     UpdateOneSegSet (bssp, intersperse_nulls);
1054     return;
1055   }
1056 
1057   /* if all of the entries in bssp->seq_set are bioseqs or nuc_prot
1058      sets, then we can convert this to a segset */
1059   for (this_sep = bssp->seq_set;
1060        this_sep != NULL && can_convert;
1061        this_sep = this_sep->next)
1062   {
1063     if (IS_Bioseq_set (this_sep))
1064     {
1065       this_bssp = (BioseqSetPtr) this_sep->data.ptrvalue;
1066       if (!IsFlatNucProtSet (this_bssp))
1067       {
1068         can_convert = FALSE;
1069       }
1070     }
1071     else if (!IS_Bioseq (this_sep))
1072     {
1073       can_convert = FALSE;
1074     }
1075   }
1076 
1077   if (can_convert)
1078   {
1079     ConvertOneSetToSegSet (sep, intersperse_nulls);
1080   }
1081   else
1082   {
1083     for (this_sep = bssp->seq_set;
1084          this_sep != NULL;
1085          this_sep = this_sep->next)
1086     {
1087       NewSegFixup (this_sep, intersperse_nulls);
1088     }
1089   }
1090 }
1091 
1092 extern void DoFixupLocus (SeqEntryPtr sep);
1093 extern void DoFixupSegSet (SeqEntryPtr sep);
1094 
NewUpdateSegSet(Pointer data)1095 static Int2 LIBCALLBACK NewUpdateSegSet (Pointer data)
1096 
1097 {
1098   OMProcControlPtr       ompcp;
1099   SeqEntryPtr            sep;
1100   ErrSev                 sev;
1101   ModalAcceptCancelData  acd;
1102   WindoW                 w;
1103   GrouP                  h, g, c;
1104   ButtoN                 intersperse_nulls_btn;
1105   ButtoN                 fix_locus_btn;
1106   ButtoN                 tax_fix_cleanup_btn;
1107   ButtoN                 b;
1108 
1109   ompcp = (OMProcControlPtr) data;
1110   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
1111   switch (ompcp->input_itemtype) {
1112     case OBJ_BIOSEQ :
1113       break;
1114     case OBJ_BIOSEQSET :
1115       break;
1116     case 0 :
1117       return OM_MSG_RET_ERROR;
1118     default :
1119       return OM_MSG_RET_ERROR;
1120   }
1121   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
1122   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
1123   if (sep == NULL) return OM_MSG_RET_ERROR;
1124 
1125   w = MovableModalWindow (-50, -33, -10, -10, "SegSet Conversion Options", NULL);
1126   h = HiddenGroup (w, -1, 0, NULL);
1127   SetGroupSpacing (h, 10, 10);
1128 
1129   g = HiddenGroup (h, 0, 4, NULL);
1130   intersperse_nulls_btn = CheckBox (g, "Intersperse NULLS", NULL);
1131   SetStatus (intersperse_nulls_btn, TRUE);
1132   fix_locus_btn = CheckBox (g, "Force Locus Fixup", NULL);
1133   SetStatus (fix_locus_btn, TRUE);
1134   tax_fix_cleanup_btn = CheckBox (g, "Do Tax_Fix/Cleanup", NULL);
1135   SetStatus (tax_fix_cleanup_btn, TRUE);
1136 
1137   acd.accepted = FALSE;
1138   acd.cancelled = FALSE;
1139   c = HiddenGroup (h, 4, 0, NULL);
1140   b = DefaultButton (c, "Accept", ModalAcceptButton);
1141   SetObjectExtra (b, &acd, NULL);
1142   b = PushButton (c, "Cancel", ModalCancelButton);
1143   SetObjectExtra (b, &acd, NULL);
1144 
1145   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
1146   RealizeWindow (w);
1147   Show (w);
1148   Update ();
1149 
1150   while (!acd.accepted && !acd.cancelled)
1151   {
1152     ProcessExternalEvent ();
1153     Update ();
1154   }
1155   ProcessAnEvent ();
1156   Hide (w);
1157   if (acd.cancelled)
1158   {
1159     Remove (w);
1160   	return OM_MSG_RET_DONE;
1161   }
1162 
1163   NewSegFixup (sep, GetStatus (intersperse_nulls_btn));
1164 
1165   if (GetStatus (fix_locus_btn))
1166   {
1167     sev = ErrSetMessageLevel (SEV_FATAL);
1168     DoFixupLocus (sep);
1169     DoFixupSegSet (sep);
1170     ErrSetMessageLevel (sev);
1171   }
1172 
1173   if (GetStatus (tax_fix_cleanup_btn))
1174   {
1175     ForceCleanupEntityID (ompcp->input_entityID);
1176   }
1177   Remove (w);
1178 
1179   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
1180   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
1181   Update ();
1182   return OM_MSG_RET_DONE;
1183 }
1184 
UpdateSegSet(Pointer data)1185 static Int2 LIBCALLBACK UpdateSegSet (Pointer data)
1186 
1187 {
1188   OMProcControlPtr  ompcp;
1189   SeqEntryPtr       sep;
1190   ErrSev            sev;
1191 
1192   ompcp = (OMProcControlPtr) data;
1193   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
1194   switch (ompcp->input_itemtype) {
1195     case OBJ_BIOSEQ :
1196       break;
1197     case OBJ_BIOSEQSET :
1198       break;
1199     case 0 :
1200       return OM_MSG_RET_ERROR;
1201     default :
1202       return OM_MSG_RET_ERROR;
1203   }
1204   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
1205   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
1206   if (sep == NULL) return OM_MSG_RET_ERROR;
1207 
1208   DoOneSegFixup (sep, TRUE);
1209   if (Message (MSG_YN, "Do you want to Force Locus Fixup?") == ANS_YES) {
1210     sev = ErrSetMessageLevel (SEV_FATAL);
1211     DoFixupLocus (sep);
1212     DoFixupSegSet (sep);
1213     ErrSetMessageLevel (sev);
1214   }
1215 
1216   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
1217   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
1218   Update ();
1219   return OM_MSG_RET_DONE;
1220 }
1221 
DoAdjustSegSeqLength(SeqEntryPtr sep,Pointer mydata,Int4 index,Int2 indent)1222 static void DoAdjustSegSeqLength (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
1223 
1224 {
1225   BioseqPtr   bsp;
1226   ValNode     head;
1227   Int4        len;
1228   Int4        len2;
1229   ValNodePtr  vnp;
1230 
1231   if (! IS_Bioseq (sep)) return;
1232   bsp = (BioseqPtr) sep->data.ptrvalue;
1233   if (bsp == NULL || bsp->repr != Seq_repr_seg) return;
1234   head.choice = SEQLOC_MIX;
1235   head.data.ptrvalue = bsp->seq_ext;
1236   head.next = NULL;
1237   vnp = NULL;
1238   len = 0;
1239   while ((vnp = SeqLocFindNext (&head, vnp)) != NULL) {
1240     len2 = SeqLocLen (vnp);
1241     if (len2 > 0) {
1242       len += len2;
1243     }
1244   }
1245   bsp->length = len;
1246 }
1247 
AdjustSegSeqLength(Pointer data)1248 static Int2 LIBCALLBACK AdjustSegSeqLength (Pointer data)
1249 
1250 {
1251   OMProcControlPtr  ompcp;
1252   SeqEntryPtr       sep;
1253 
1254   ompcp = (OMProcControlPtr) data;
1255   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
1256   switch (ompcp->input_itemtype) {
1257     case OBJ_BIOSEQ :
1258       break;
1259     case OBJ_BIOSEQSET :
1260       break;
1261     case 0 :
1262       return OM_MSG_RET_ERROR;
1263     default :
1264       return OM_MSG_RET_ERROR;
1265   }
1266   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
1267   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
1268   if (sep == NULL) return OM_MSG_RET_ERROR;
1269   SeqEntryExplore (sep, NULL, DoAdjustSegSeqLength);
1270   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
1271   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
1272   return OM_MSG_RET_DONE;
1273 }
1274 
1275 
ReduceLocationToSingleBioseq(SeqLocPtr slp,BioseqPtr bsp)1276 static SeqLocPtr ReduceLocationToSingleBioseq (SeqLocPtr slp, BioseqPtr bsp)
1277 {
1278   SeqLocPtr this_slp, prev_slp, next_slp;
1279   BioseqPtr this_bsp;
1280   SeqIntPtr sint;
1281   ValNodePtr this_vnp, prev_vnp, next_vnp;
1282 
1283   if (slp == NULL || bsp == NULL) return NULL;
1284 
1285   if (slp->choice == SEQLOC_MIX)
1286   {
1287     this_slp = slp->data.ptrvalue;
1288     prev_slp = NULL;
1289     while (this_slp != NULL)
1290     {
1291       next_slp = this_slp->next;
1292       this_bsp = BioseqFind (SeqLocId (this_slp));
1293       if (this_bsp != bsp)
1294       {
1295         if (prev_slp == NULL)
1296         {
1297           slp->data.ptrvalue = next_slp;
1298         }
1299         else
1300         {
1301           prev_slp->next = next_slp;
1302         }
1303         this_slp->next = NULL;
1304         SeqLocFree (this_slp);
1305       }
1306       else
1307       {
1308         prev_slp = this_slp;
1309       }
1310       this_slp = next_slp;
1311     }
1312     if (slp->data.ptrvalue == NULL)
1313     {
1314       slp = SeqLocFree (slp);
1315     }
1316     else
1317     {
1318       this_slp = slp->data.ptrvalue;
1319       if (this_slp->next == NULL)
1320       {
1321         slp->data.ptrvalue = NULL;
1322         slp = SeqLocFree (slp);
1323         slp = this_slp;
1324       }
1325     }
1326   }
1327   else if (slp->choice == SEQLOC_PACKED_INT)
1328   {
1329     prev_vnp = NULL;
1330     this_vnp = slp->data.ptrvalue;
1331     while (this_vnp != NULL)
1332     {
1333       next_vnp = this_vnp->next;
1334       sint = this_vnp->data.ptrvalue;
1335       this_bsp = BioseqFind (sint->id);
1336       if (this_bsp != bsp)
1337       {
1338         if (prev_vnp == NULL) {
1339           slp->data.ptrvalue = next_vnp;
1340         } else {
1341           prev_vnp->next = next_vnp;
1342         }
1343         this_vnp->next = NULL;
1344         sint = SeqIntFree (sint);
1345         this_vnp = ValNodeFree (this_vnp);
1346       } else {
1347         prev_vnp = this_vnp;
1348       }
1349       this_vnp = next_vnp;
1350     }
1351     if (slp->data.ptrvalue == NULL)
1352     {
1353       slp = SeqLocFree (slp);
1354     }
1355   }
1356   else
1357   {
1358     this_bsp = BioseqFind (SeqLocId (slp));
1359     if (this_bsp != bsp)
1360     {
1361       slp = SeqLocFree (slp);
1362     }
1363   }
1364   return slp;
1365 }
1366 
RemoveBioseqFromLocation(SeqLocPtr slp,BioseqPtr bsp)1367 static SeqLocPtr RemoveBioseqFromLocation (SeqLocPtr slp, BioseqPtr bsp)
1368 {
1369   SeqLocPtr this_slp, prev_slp, next_slp;
1370   BioseqPtr this_bsp;
1371   SeqIntPtr sint;
1372   ValNodePtr this_vnp, prev_vnp, next_vnp;
1373 
1374   if (slp == NULL || bsp == NULL) return NULL;
1375 
1376   if (slp->choice == SEQLOC_MIX)
1377   {
1378     this_slp = slp->data.ptrvalue;
1379     prev_slp = NULL;
1380     while (this_slp != NULL)
1381     {
1382       next_slp = this_slp->next;
1383       this_bsp = BioseqFind (SeqLocId (this_slp));
1384       if (this_bsp == bsp)
1385       {
1386         if (prev_slp == NULL)
1387         {
1388           slp->data.ptrvalue = next_slp;
1389         }
1390         else
1391         {
1392           prev_slp->next = next_slp;
1393         }
1394         this_slp->next = NULL;
1395         SeqLocFree (this_slp);
1396       }
1397       else
1398       {
1399         prev_slp = this_slp;
1400       }
1401       this_slp = next_slp;
1402     }
1403     if (slp->data.ptrvalue == NULL)
1404     {
1405       slp = SeqLocFree (slp);
1406     }
1407     else
1408     {
1409       this_slp = slp->data.ptrvalue;
1410       if (this_slp->next == NULL)
1411       {
1412         slp->data.ptrvalue = NULL;
1413         slp = SeqLocFree (slp);
1414         slp = this_slp;
1415       }
1416     }
1417   }
1418   else if (slp->choice == SEQLOC_PACKED_INT)
1419   {
1420     prev_vnp = NULL;
1421     this_vnp = slp->data.ptrvalue;
1422     while (this_vnp != NULL)
1423     {
1424       next_vnp = this_vnp->next;
1425       sint = this_vnp->data.ptrvalue;
1426       this_bsp = BioseqFind (sint->id);
1427       if (this_bsp == bsp)
1428       {
1429         if (prev_vnp == NULL) {
1430           slp->data.ptrvalue = next_vnp;
1431         } else {
1432           prev_vnp->next = next_vnp;
1433         }
1434         this_vnp->next = NULL;
1435         sint = SeqIntFree (sint);
1436         this_vnp = ValNodeFree (this_vnp);
1437       } else {
1438         prev_vnp = this_vnp;
1439       }
1440       this_vnp = next_vnp;
1441     }
1442     if (slp->data.ptrvalue == NULL)
1443     {
1444       slp = SeqLocFree (slp);
1445     }
1446   }
1447   else
1448   {
1449     this_bsp = BioseqFind (SeqLocId (slp));
1450     if (this_bsp == bsp)
1451     {
1452       slp = SeqLocFree (slp);
1453     }
1454   }
1455   return slp;
1456 }
1457 
PushFeaturesDownToBioseq(SeqAnnotPtr annot,SeqEntryPtr sep)1458 static void PushFeaturesDownToBioseq (SeqAnnotPtr annot, SeqEntryPtr sep)
1459 {
1460   BioseqSetPtr bssp;
1461   BioseqPtr    bsp;
1462   SeqFeatPtr   sfp, prev_sfp, last_sfp, next_sfp;
1463 
1464   if (annot == NULL || annot->type != 1 || sep == NULL) return;
1465 
1466   if (IS_Bioseq_set (sep)) {
1467     bssp = sep->data.ptrvalue;
1468     for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
1469       PushFeaturesDownToBioseq (annot, sep);
1470     }
1471     return;
1472   }
1473 
1474   if (! IS_Bioseq (sep)) return;
1475 
1476   bsp = sep->data.ptrvalue;
1477 
1478   sfp = annot->data;
1479   prev_sfp = NULL;
1480   while (sfp != NULL) {
1481     next_sfp = sfp->next;
1482     while (sfp != NULL && ! SeqIdIn (SeqLocId (sfp->location), bsp->id)) {
1483       prev_sfp = sfp;
1484       sfp = sfp->next;
1485       if (sfp != NULL) {
1486         next_sfp = sfp->next;
1487       }
1488     }
1489     if (sfp != NULL) {
1490       if (bsp->annot == NULL) {
1491         bsp->annot = SeqAnnotNew ();
1492         bsp->annot->type = 1;
1493         bsp->annot->data = sfp;
1494       } else {
1495         if (bsp->annot->data == NULL) {
1496           bsp->annot->data = sfp;
1497         } else {
1498           last_sfp = bsp->annot->data;
1499           while (last_sfp->next != NULL) {
1500             last_sfp = last_sfp->next;
1501           }
1502           last_sfp->next = sfp;
1503         }
1504       }
1505       if (prev_sfp == NULL) {
1506         annot->data = sfp->next;
1507       } else {
1508         prev_sfp->next = sfp->next;
1509       }
1510       sfp->next = NULL;
1511       sfp = next_sfp;
1512     }
1513   }
1514 }
1515 
1516 static void
SplitSegmentedProduct(BioseqPtr old_protein,BioseqPtr new_protein,Int4 protein_offset)1517 SplitSegmentedProduct
1518 (BioseqPtr old_protein,
1519  BioseqPtr new_protein,
1520  Int4      protein_offset)
1521 {
1522   SeqFeatPtr        sfp, copy_sfp, new_sfp;
1523   SeqMgrFeatContext fcontext;
1524   Int4              right_end;
1525   SeqLoc            subtract_loc;
1526   SeqInt            sint;
1527   Boolean           partial3;
1528   Boolean           partial5;
1529 
1530   if (new_protein == NULL)
1531   {
1532     return;
1533   }
1534 
1535   /* delete full length feature on new protein */
1536   sfp = SeqMgrGetNextFeature (new_protein, NULL, 0, 0, &fcontext);
1537   if (sfp != NULL)
1538   {
1539     sfp->idx.deleteme = TRUE;
1540   }
1541 
1542   right_end = protein_offset + new_protein->length - 1;
1543 
1544   /* if there are features on the original protein product
1545    * other than the full-length feature, we need to find the offsets
1546    * so that we can determine whether they belong in this product.
1547    */
1548   sfp = SeqMgrGetNextFeature (old_protein, NULL, 0, 0, &fcontext);
1549   while (sfp != NULL)
1550   {
1551     new_sfp = NULL;
1552     if ((fcontext.left == 0 && fcontext.right == old_protein->length - 1)
1553         || (fcontext.left <= protein_offset && fcontext.right >= right_end))
1554     {
1555       copy_sfp = SeqFeatCopy (sfp);
1556       new_sfp = CreateNewFeatureOnBioseq (new_protein, copy_sfp->data.choice, NULL);
1557       new_sfp->data.value.ptrvalue = copy_sfp->data.value.ptrvalue;
1558       copy_sfp->data.value.ptrvalue = NULL;
1559       copy_sfp = SeqFeatFree (copy_sfp);
1560     }
1561     else if ((fcontext.left <= protein_offset && fcontext.right >= protein_offset)
1562              || (fcontext.left <= right_end && fcontext.right >= right_end)
1563              || (fcontext.left >= protein_offset && fcontext.right <= protein_offset))
1564     {
1565       copy_sfp = SeqFeatCopy (sfp);
1566       new_sfp = CreateNewFeatureOnBioseq (new_protein, copy_sfp->data.choice, NULL);
1567       new_sfp->data.value.ptrvalue = copy_sfp->data.value.ptrvalue;
1568       copy_sfp->data.value.ptrvalue = NULL;
1569       copy_sfp = SeqFeatFree (copy_sfp);
1570       subtract_loc.next = NULL;
1571       subtract_loc.choice = SEQLOC_INT;
1572       subtract_loc.data.ptrvalue = &sint;
1573       sint.id = new_protein->id;
1574       sint.strand = Seq_strand_plus;
1575       sint.if_from = NULL;
1576       sint.if_to = NULL;
1577 
1578       /* chop off left end if needed */
1579       if (fcontext.left > protein_offset)
1580       {
1581         sint.from = 0;
1582         sint.to = fcontext.left - protein_offset - 1;
1583         new_sfp->location = SeqLocSubtract (new_sfp->location, &subtract_loc);
1584       }
1585       /* chop off right end if needed */
1586       if (fcontext.right < right_end)
1587       {
1588         sint.from = fcontext.right - protein_offset + 1;
1589         sint.to = new_protein->length - 1;
1590         new_sfp->location = SeqLocSubtract (new_sfp->location, &subtract_loc);
1591       }
1592     }
1593     if (new_sfp != NULL)
1594     {
1595       partial3 = FALSE;
1596       partial5 = FALSE;
1597       if (fcontext.left < protein_offset)
1598       {
1599         partial5 = TRUE;
1600       }
1601       if (fcontext.right > right_end)
1602       {
1603         partial3 = TRUE;
1604       }
1605 
1606       if (partial3 || partial5)
1607       {
1608         SetSeqLocPartial (new_sfp->location, partial5, partial3);
1609         new_sfp->partial = TRUE;
1610       }
1611 
1612     }
1613     sfp = SeqMgrGetNextFeature (old_protein, sfp, 0, 0, &fcontext);
1614   }
1615 }
1616 
SplitSegmentedFeatsOnOneSet(BioseqSetPtr set)1617 static void SplitSegmentedFeatsOnOneSet (BioseqSetPtr set)
1618 {
1619   SeqAnnotPtr annot, prev_annot, next_annot;
1620   SeqFeatPtr  sfp, new_sfp, prev_sfp, next_sfp;
1621   SeqEntryPtr sep, set_sep;
1622   BioseqPtr   bsp, last_bsp;
1623   SeqLocPtr   loc, slp;
1624   Int4        product_offset, protein_offset;
1625   Boolean     is_first = TRUE;
1626   SeqIdPtr    sip;
1627   CdRegionPtr crp;
1628   Boolean     partial3, partial5;
1629   Int4        len_modulo, new_frame;
1630 
1631   if (set == NULL || set->annot == NULL) return;
1632 
1633   set_sep = SeqMgrGetSeqEntryForData (set);
1634 
1635   prev_annot = NULL;
1636   annot = set->annot;
1637   next_annot = annot->next;
1638   while (annot != NULL) {
1639     next_annot = annot->next;
1640     if (annot->type != 1) {
1641       prev_annot = annot;
1642       annot = next_annot;
1643       continue;
1644     }
1645     sfp = annot->data;
1646     while (sfp != NULL) {
1647       next_sfp = sfp->next;
1648       prev_sfp = sfp;
1649       loc = SeqLocFindNext (sfp->location, NULL);
1650       sip = SeqLocId (loc);
1651       last_bsp = BioseqFind (sip);
1652 
1653       product_offset = 0;
1654       slp = SeqLocFindNext (sfp->location, loc);
1655       while (slp != NULL) {
1656         bsp = BioseqFind (SeqLocId (slp));
1657         if (bsp != last_bsp && last_bsp != NULL) {
1658           new_sfp = SeqFeatCopy (sfp);
1659           new_sfp->location = ReduceLocationToSingleBioseq (new_sfp->location, last_bsp);
1660           sfp->location = RemoveBioseqFromLocation (sfp->location, last_bsp);
1661           if (is_first)
1662           {
1663             CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
1664             SetSeqLocPartial (sfp->location, TRUE, partial3);
1665             is_first = FALSE;
1666             sfp->partial = TRUE;
1667             SetSeqLocPartial (new_sfp->location, partial5, TRUE);
1668             new_sfp->partial = TRUE;
1669           }
1670           else
1671           {
1672             SetSeqLocPartial (new_sfp->location, TRUE, TRUE);
1673             new_sfp->partial = TRUE;
1674           }
1675 
1676           if (sfp->data.choice == SEQFEAT_CDREGION && sfp->product != NULL)
1677           {
1678             /* now figure out protein offset, to use for copying protein features */
1679             if (SeqLocStrand (new_sfp->location) == Seq_strand_minus)
1680             {
1681               /* if on minus strand, offset is length of remaining location */
1682               protein_offset = SeqLocLen (sfp->location) / 3;
1683               len_modulo = SeqLocLen (sfp->location) % 3;
1684             }
1685             else
1686             {
1687               /* if on plus strand, offset is locations already removed */
1688               protein_offset = product_offset / 3;
1689               len_modulo = (product_offset + SeqLocLen (new_sfp->location)) % 3;
1690             }
1691             crp = (CdRegionPtr) sfp->data.value.ptrvalue;
1692             if (crp != NULL && (crp->frame == 2 || crp->frame == 3))
1693             {
1694               protein_offset --;
1695             }
1696 
1697             /* correct frame */
1698             if (crp != NULL) {
1699               new_frame = 0;
1700               if (len_modulo == 0)
1701               {
1702                 new_frame = crp->frame;
1703               }
1704               else if (crp->frame == 0 || crp->frame == 1)
1705               {
1706                 if (len_modulo == 1)
1707                 {
1708                   new_frame = 2;
1709                 }
1710                 else
1711                 {
1712                   /* len_modulo == 2 */
1713                   new_frame = 3;
1714                 }
1715               }
1716               else if (len_modulo == 1)
1717               {
1718                 if (crp->frame == 2)
1719                 {
1720                   new_frame = 1;
1721                 }
1722                 else
1723                 {
1724                   /* crp->frame == 3 */
1725                   new_frame = 2;
1726                 }
1727 
1728               }
1729               else if (len_modulo == 2)
1730               {
1731                 if (crp->frame == 2)
1732                 {
1733                   new_frame = 3;
1734                 }
1735                 else
1736                 {
1737                   /* crp->frame == 3 */
1738                   new_frame = 1;
1739                 }
1740               }
1741               crp->frame = new_frame;
1742             }
1743 
1744             new_sfp->product = SeqLocFree (new_sfp->product);
1745             SeqEdTranslateOneCDS (new_sfp, last_bsp, sfp->idx.entityID, Sequin_GlobalAlign2Seq);
1746 
1747             SplitSegmentedProduct (BioseqFindFromSeqLoc (sfp->product),
1748                                    BioseqFindFromSeqLoc (new_sfp->product),
1749                                    protein_offset);
1750             ResynchCDSPartials (new_sfp, NULL);
1751           }
1752 
1753           prev_sfp->next = new_sfp;
1754           new_sfp->next = next_sfp;
1755           prev_sfp = new_sfp;
1756           product_offset += SeqLocLen (slp);
1757           slp = SeqLocFindNext (sfp->location, NULL);
1758           last_bsp = bsp;
1759         } else {
1760           product_offset += SeqLocLen (slp);
1761           slp = SeqLocFindNext (sfp->location, slp);
1762         }
1763       }
1764       if (sfp->location == NULL)
1765       {
1766         sfp->idx.deleteme = TRUE;
1767       }
1768       else if (!is_first)
1769       {
1770         CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
1771         SetSeqLocPartial (sfp->location, TRUE, partial3);
1772         sfp->partial = TRUE;
1773         if (sfp->data.choice == SEQFEAT_CDREGION && sfp->product != NULL)
1774         {
1775           SeqEdTranslateOneCDS (sfp, last_bsp, sfp->idx.entityID, Sequin_GlobalAlign2Seq);
1776 
1777           ResynchCDSPartials (sfp, NULL);
1778         }
1779       }
1780       sfp = next_sfp;
1781     }
1782 
1783     /* push features to appropriate bioseqs */
1784     for (sep = set->seq_set; sep != NULL; sep = sep->next) {
1785       PushFeaturesDownToBioseq (annot, sep);
1786     }
1787     if (prev_annot == NULL) {
1788       set->annot = annot->next;
1789     } else {
1790       prev_annot->next = annot->next;
1791     }
1792     annot->next = NULL;
1793     SeqAnnotFree (annot);
1794     annot = next_annot;
1795   }
1796 }
1797 
SplitSegmentedFeats(SeqEntryPtr sep,Uint2 entityID)1798 static void SplitSegmentedFeats (SeqEntryPtr sep, Uint2 entityID)
1799 {
1800   BioseqSetPtr bssp;
1801 
1802   if (IS_Bioseq_set (sep)) {
1803     bssp = (BioseqSetPtr) sep->data.ptrvalue;
1804     SplitSegmentedFeatsOnOneSet (bssp);
1805     for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
1806       SplitSegmentedFeats (sep, entityID);
1807     }
1808   }
1809   DeleteMarkedObjects (entityID, 0, NULL);
1810 }
1811 
SplitSegmentedFeatsMenuItem(IteM i)1812 extern void SplitSegmentedFeatsMenuItem (IteM i)
1813 {
1814   BaseFormPtr   bfp;
1815   SeqEntryPtr   sep;
1816 
1817 #ifdef WIN_MAC
1818   bfp = currentFormDataPtr;
1819 #else
1820   bfp = GetObjectExtra (i);
1821 #endif
1822   if (bfp == NULL) return;
1823   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1824   if (sep == NULL) return;
1825   SplitSegmentedFeats (sep, bfp->input_entityID);
1826   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1827   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1828 
1829 }
1830 
DoSegSetUndo(BioseqPtr segseq,BioseqSetPtr parts,BioseqSetPtr segset,Uint2 entityID)1831 static void DoSegSetUndo (BioseqPtr segseq, BioseqSetPtr parts, BioseqSetPtr segset, Uint2 entityID)
1832 
1833 {
1834   SeqAnnotPtr  annot;
1835   ValNodePtr   descr;
1836   SeqAnnotPtr  sap;
1837   SeqEntryPtr  tmp;
1838   SeqEntryPtr  split_sep;
1839   Uint2        parenttype;
1840   Pointer      parentptr;
1841   BioseqSetPtr parent_bssp = NULL;
1842 
1843   if (segseq == NULL || parts == NULL || parts->seq_set == NULL || segset == NULL) return;
1844 
1845   /* split segmented features before undoing segset */
1846   split_sep = SeqMgrGetSeqEntryForData (segset);
1847   GetSeqEntryParent (split_sep, &parentptr, &parenttype);
1848   if (parenttype == OBJ_BIOSEQSET && parentptr != NULL)
1849   {
1850     parent_bssp = (BioseqSetPtr) parentptr;
1851     if (parent_bssp->_class == BioseqseqSet_class_nuc_prot)
1852     {
1853       split_sep = SeqMgrGetSeqEntryForData (parent_bssp);
1854     }
1855   }
1856   SplitSegmentedFeats (split_sep, entityID);
1857 
1858   segset->_class = 7;
1859   parts->_class = 14;
1860   annot = segseq->annot;
1861   segseq->annot = NULL;
1862   if (segset->annot == NULL) {
1863     segset->annot = annot;
1864     annot = NULL;
1865   } else {
1866     sap = segset->annot;
1867     while (sap->next != NULL) {
1868       sap = sap->next;
1869     }
1870     sap->next = annot;
1871   }
1872   descr = segseq->descr;
1873   segseq->descr = NULL;
1874   ValNodeLink (&(segset->descr), descr);
1875   tmp = segset->seq_set;
1876   if (tmp != NULL && IS_Bioseq (tmp)) {
1877     segset->seq_set = tmp->next;
1878     tmp->next = NULL;
1879     SeqEntryFree (tmp);
1880   }
1881 
1882   /* propagate the descriptors on the segset to the parts in the set */
1883   SetDescriptorPropagate (segset);
1884   SetDescriptorPropagate (parts);
1885 
1886 }
1887 
DoOneSegUndo(SeqEntryPtr sep,Uint2 entityID)1888 static Int2 DoOneSegUndo (SeqEntryPtr sep, Uint2 entityID)
1889 
1890 {
1891   BioseqSetPtr    bssp;
1892   Int2            count = 0;
1893   UpdateSegStruc  uss;
1894 
1895   if (sep == NULL) return 0;
1896   if (IS_Bioseq_set (sep)) {
1897     bssp = (BioseqSetPtr) sep->data.ptrvalue;
1898     if (bssp != NULL && (bssp->_class == 7 ||
1899                          (IsPopPhyEtcSet (bssp->_class)))) {
1900       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
1901         count += DoOneSegUndo (sep, entityID);
1902       }
1903       return count;
1904     }
1905   }
1906 
1907   uss.segseq = NULL;
1908   uss.parts = NULL;
1909   uss.segset = NULL;
1910   UpdateSegExplore (sep, (Pointer) &uss, FindSegSetComponentsCallback);
1911   if (uss.segseq != NULL && uss.parts != NULL && uss.segset != NULL) {
1912     DoSegSetUndo (uss.segseq, uss.parts, uss.segset, entityID);
1913     return 1;
1914   }
1915   return 0;
1916 }
1917 
BioseqExtract(SeqEntryPtr top,BioseqPtr bsp)1918 static SeqEntryPtr BioseqExtract (SeqEntryPtr top, BioseqPtr bsp)
1919 
1920 {
1921   BioseqSetPtr  bssp;
1922   SeqEntryPtr   next;
1923   SeqEntryPtr   PNTR prev;
1924   SeqEntryPtr   rsult = NULL;
1925   SeqEntryPtr   sep;
1926 
1927   if (top == NULL || bsp == NULL) return NULL;
1928   if (! IS_Bioseq_set (top)) return NULL;
1929   bssp = (BioseqSetPtr) top->data.ptrvalue;
1930   if (bssp == NULL) return NULL;
1931   prev = &(bssp->seq_set);
1932   sep = bssp->seq_set;
1933   while (sep != NULL) {
1934     next = sep->next;
1935     if (IS_Bioseq_set (sep)) {
1936       rsult = BioseqExtract (sep, bsp);
1937       if (rsult != NULL) {
1938         return rsult;
1939       }
1940       prev = &(sep->next);
1941       sep = next;
1942     } else if (IS_Bioseq (sep) && sep->data.ptrvalue == (Pointer) bsp) {
1943       *(prev) = next;
1944       sep->next = NULL;
1945       return sep;
1946     } else {
1947       prev = &(sep->next);
1948       sep = next;
1949     }
1950   }
1951   return NULL;
1952 }
1953 
DoRepairPartsSet(SeqEntryPtr sep)1954 static void DoRepairPartsSet (SeqEntryPtr sep)
1955 
1956 {
1957   BioseqPtr       bsp;
1958   BioseqSetPtr    bssp;
1959   ValNode         head;
1960   BioseqSetPtr    parts;
1961   BioseqPtr       segseq;
1962   SeqLocPtr       slp;
1963   SeqEntryPtr     tmp;
1964   UpdateSegStruc  uss;
1965 
1966   if (sep == NULL) return;
1967   if (IS_Bioseq (sep)) return;
1968   if (IS_Bioseq_set (sep)) {
1969     bssp = (BioseqSetPtr) sep->data.ptrvalue;
1970     if (bssp == NULL) return;
1971     if (bssp->_class == 7 ||
1972         (IsPopPhyEtcSet (bssp->_class))) {
1973       for (tmp = bssp->seq_set; tmp != NULL; tmp = tmp->next) {
1974         DoRepairPartsSet (tmp);
1975       }
1976       return;
1977     }
1978   }
1979   uss.segseq = NULL;
1980   uss.parts = NULL;
1981   uss.segset = NULL;
1982   UpdateSegExplore (sep, (Pointer) &uss, FindSegSetComponentsCallback);
1983   if (uss.segseq == NULL || uss.parts == NULL || uss.segset == NULL) return;
1984   segseq = uss.segseq;
1985   parts = uss.parts;
1986   if (segseq->repr != Seq_repr_seg ||
1987       segseq->seq_ext_type != 1 ||
1988       segseq->seq_ext == NULL) return;
1989   head.choice = SEQLOC_MIX;
1990   head.data.ptrvalue = segseq->seq_ext;
1991   head.next = NULL;
1992   slp = NULL;
1993   while ((slp = SeqLocFindNext (&head, slp)) != NULL) {
1994     bsp = BioseqFind (SeqLocId (slp));
1995     if (bsp != NULL) {
1996       tmp = BioseqExtract (sep, bsp);
1997       if (tmp != NULL) {
1998         ValNodeLink (&parts->seq_set, tmp);
1999       }
2000     }
2001   }
2002 }
2003 
2004 
RepackageParksInPartsSetForEntityID(Uint2 entityID)2005 static void RepackageParksInPartsSetForEntityID (Uint2 entityID)
2006 {
2007   ObjMgrDataPtr     omdptop;
2008   ObjMgrData        omdata;
2009   Uint2             parenttype;
2010   Pointer           parentptr;
2011   SeqEntryPtr       sep;
2012 
2013   sep = GetTopSeqEntryForEntityID (entityID);
2014   if (sep == NULL) return;
2015   SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
2016   GetSeqEntryParent (sep, &parentptr, &parenttype);
2017   DoRepairPartsSet (sep);
2018   SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
2019   RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
2020   ObjMgrSetDirtyFlag (entityID, TRUE);
2021   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
2022 }
2023 
2024 
PackagePartsInPartsSet(Pointer data)2025 static Int2 LIBCALLBACK PackagePartsInPartsSet (Pointer data)
2026 
2027 {
2028   OMProcControlPtr  ompcp;
2029 
2030   ompcp = (OMProcControlPtr) data;
2031   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
2032   switch (ompcp->input_itemtype) {
2033     case OBJ_BIOSEQ :
2034       break;
2035     case OBJ_BIOSEQSET :
2036       break;
2037     case 0 :
2038       return OM_MSG_RET_ERROR;
2039     default :
2040       return OM_MSG_RET_ERROR;
2041   }
2042   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
2043   RepackageParksInPartsSetForEntityID (ompcp->input_entityID);
2044   return OM_MSG_RET_DONE;
2045 }
2046 
2047 
RepackagePartsMenuItem(IteM i)2048 NLM_EXTERN void RepackagePartsMenuItem (IteM i)
2049 {
2050   BaseFormPtr bfp;
2051 
2052 #ifdef WIN_MAC
2053   bfp = currentFormDataPtr;
2054 #else
2055   bfp = GetObjectExtra (i);
2056 #endif
2057   if (bfp == NULL) return;
2058   RepackageParksInPartsSetForEntityID (bfp->input_entityID);
2059 }
2060 
2061 
RemoveDupGenBankSets(SeqEntryPtr sep)2062 NLM_EXTERN void RemoveDupGenBankSets (SeqEntryPtr sep)
2063 
2064 {
2065   SeqAnnotPtr   annot;
2066   BioseqSetPtr  bssp;
2067   ValNodePtr    descr;
2068   SeqAnnotPtr   sap;
2069   SeqEntryPtr   tmp;
2070   BioseqSetPtr  tmpbssp;
2071 
2072   if (sep == NULL || ! IS_Bioseq_set (sep)) return;
2073   bssp = (BioseqSetPtr) sep->data.ptrvalue;
2074   if (bssp == NULL || bssp->_class != 7) return;
2075   tmp = bssp->seq_set;
2076   if (tmp == NULL || ! IS_Bioseq_set (tmp) || tmp->next != NULL) return;
2077   tmpbssp = (BioseqSetPtr) tmp->data.ptrvalue;
2078   if (tmpbssp == NULL || tmpbssp->_class != 7 || tmpbssp->seq_set == NULL) return;
2079   annot = tmpbssp->annot;
2080   tmpbssp->annot = NULL;
2081   if (bssp->annot == NULL) {
2082     bssp->annot = annot;
2083     annot = NULL;
2084   } else {
2085     sap = bssp->annot;
2086     while (sap->next != NULL) {
2087       sap = sap->next;
2088     }
2089     sap->next = annot;
2090   }
2091   descr = tmpbssp->descr;
2092   tmpbssp->descr = NULL;
2093   ValNodeLink (&(bssp->descr), descr);
2094   bssp->seq_set = tmpbssp->seq_set;
2095   tmpbssp->seq_set = NULL;
2096   SeqEntryFree (tmp);
2097 }
2098 
UndoSegSet(Pointer data)2099 static Int2 LIBCALLBACK UndoSegSet (Pointer data)
2100 
2101 {
2102   Int2              count;
2103   ObjMgrDataPtr     omdptop;
2104   ObjMgrData        omdata;
2105   OMProcControlPtr  ompcp;
2106   Uint2             parenttype;
2107   Pointer           parentptr;
2108   SeqEntryPtr       sep;
2109 
2110   ompcp = (OMProcControlPtr) data;
2111   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
2112   switch (ompcp->input_itemtype) {
2113     case OBJ_BIOSEQ :
2114       break;
2115     case OBJ_BIOSEQSET :
2116       break;
2117     case 0 :
2118       return OM_MSG_RET_ERROR;
2119     default :
2120       break;
2121   }
2122   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
2123   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
2124   if (sep == NULL) return OM_MSG_RET_ERROR;
2125   SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
2126   GetSeqEntryParent (sep, &parentptr, &parenttype);
2127   count = DoOneSegUndo (sep, ompcp->input_entityID);
2128   RemoveDupGenBankSets (sep);
2129   SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
2130   RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
2131   if (count > 0) {
2132     PropagateFromGenBankBioseqSet (sep, FALSE);
2133     SeqMgrClearFeatureIndexes (ompcp->input_entityID, NULL);
2134     SeqMgrIndexFeatures (ompcp->input_entityID, NULL);
2135     SplitSegmentedFeats (sep, ompcp->input_entityID);
2136     ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
2137     ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
2138   }
2139   return OM_MSG_RET_DONE;
2140 }
2141 
2142 static Boolean
ProteinUsedForThisSegmentInThisAnnotList(SeqEntryPtr seg_sep,SeqEntryPtr prot_sep,SeqAnnotPtr sap)2143 ProteinUsedForThisSegmentInThisAnnotList
2144 (SeqEntryPtr seg_sep,
2145  SeqEntryPtr prot_sep,
2146  SeqAnnotPtr sap)
2147 {
2148   SeqFeatPtr sfp;
2149   BioseqPtr  seg_bsp, prot_bsp;
2150   SeqIdPtr   loc_id, prot_id;
2151 
2152   if (seg_sep == NULL || ! IS_Bioseq (seg_sep) || seg_sep->data.ptrvalue == NULL
2153       || prot_sep == NULL || ! IS_Bioseq (prot_sep) || prot_sep->data.ptrvalue == NULL
2154       || sap == NULL)
2155   {
2156     return FALSE;
2157   }
2158 
2159   seg_bsp = seg_sep->data.ptrvalue;
2160   prot_bsp = prot_sep->data.ptrvalue;
2161 
2162   if (sap->type == 1)
2163   {
2164     sfp = sap->data;
2165     while (sfp != NULL)
2166     {
2167       loc_id = SeqLocId (sfp->location);
2168       prot_id = SeqLocId (sfp->product);
2169       if (SeqIdIn (loc_id, seg_bsp->id) && SeqIdIn (prot_id, prot_bsp->id))
2170       {
2171         return TRUE;
2172       }
2173       sfp = sfp->next;
2174     }
2175   }
2176   return ProteinUsedForThisSegmentInThisAnnotList (seg_sep, prot_sep, sap->next);
2177 }
2178 
RemoveIntermediateGenBankWrapper(BioseqSetPtr bssp)2179 static void RemoveIntermediateGenBankWrapper (BioseqSetPtr bssp)
2180 {
2181   SeqEntryPtr  this_sep, next_sep, prev_sep, last_mem_sep;
2182   Uint2        parenttype;
2183   Pointer      parentptr;
2184   BioseqSetPtr parent_bssp;
2185 
2186   if (bssp == NULL || bssp->_class != BioseqseqSet_class_genbank)
2187   {
2188     return;
2189   }
2190   this_sep = SeqMgrGetSeqEntryForData (bssp);
2191   GetSeqEntryParent (this_sep, &parentptr, &parenttype);
2192   if (parenttype != OBJ_BIOSEQSET || parentptr == NULL)
2193   {
2194     return;
2195   }
2196   parent_bssp = (BioseqSetPtr) parentptr;
2197 
2198   if (parent_bssp->_class != BioseqseqSet_class_genbank)
2199   {
2200     return;
2201   }
2202 
2203   /* propagate descriptors on our original set to its members */
2204   SetDescriptorPropagate (bssp);
2205 
2206   /* put the set members in the parent list where the set was */
2207   last_mem_sep = bssp->seq_set;
2208   while (last_mem_sep != NULL && last_mem_sep->next != NULL)
2209   {
2210     last_mem_sep = last_mem_sep->next;
2211   }
2212 
2213   next_sep = this_sep->next;
2214   this_sep->next = NULL;
2215 
2216   if (parent_bssp->seq_set == this_sep)
2217   {
2218     if (last_mem_sep == NULL)
2219     {
2220       parent_bssp->seq_set = next_sep;
2221     }
2222     else
2223     {
2224       parent_bssp->seq_set = bssp->seq_set;
2225       last_mem_sep->next = next_sep;
2226     }
2227   }
2228   else
2229   {
2230     prev_sep = parent_bssp->seq_set;
2231     while (prev_sep->next != this_sep)
2232     {
2233       prev_sep = prev_sep->next;
2234     }
2235     if (last_mem_sep == NULL)
2236     {
2237       prev_sep->next = next_sep;
2238     }
2239     else
2240     {
2241       prev_sep->next = bssp->seq_set;
2242       last_mem_sep->next = next_sep;
2243     }
2244   }
2245 
2246   bssp->seq_set = NULL;
2247   SeqEntryFree (this_sep);
2248 }
2249 
SetContainsProteins(BioseqSetPtr bssp)2250 static Boolean SetContainsProteins (BioseqSetPtr bssp)
2251 {
2252   BioseqPtr   bsp;
2253   SeqEntryPtr sep;
2254   Boolean     has_proteins = FALSE;
2255 
2256   if (bssp == NULL || bssp->seq_set == NULL)
2257   {
2258     return FALSE;
2259   }
2260 
2261   for (sep = bssp->seq_set; sep != NULL && !has_proteins; sep = sep->next)
2262   {
2263     if (sep->data.ptrvalue == NULL)
2264     {
2265       continue;
2266     }
2267     if (IS_Bioseq (sep))
2268     {
2269       bsp = (BioseqPtr) sep->data.ptrvalue;
2270       if (ISA_aa (bsp->mol))
2271       {
2272         has_proteins = TRUE;
2273       }
2274     }
2275     else if (IS_Bioseq_set (sep))
2276     {
2277       has_proteins |= SetContainsProteins (sep->data.ptrvalue);
2278     }
2279   }
2280   return has_proteins;
2281 }
2282 
2283 static void
RemoveOneSegSet(SeqEntryPtr this_sep,BioseqSetPtr parent_bssp,BioseqSetPtr target_bssp,Uint2 entityID)2284 RemoveOneSegSet
2285 (SeqEntryPtr       this_sep,
2286  BioseqSetPtr      parent_bssp,
2287  BioseqSetPtr      target_bssp,
2288  Uint2             entityID)
2289 {
2290   SeqEntryPtr  protein_list = NULL;
2291   SeqEntryPtr  seg_list, seg_sep, prot_sep;
2292   SeqEntryPtr  prev_prot_sep, next_prot_sep;
2293   BioseqPtr    seg_bsp;
2294   SeqEntryPtr  this_prot_list, last_this;
2295   BioseqSetPtr seg_nuc_prot, seg_bssp;
2296   SeqEntryPtr  next_seg;
2297 
2298   if (this_sep == NULL)
2299   {
2300     return;
2301   }
2302 
2303   DoOneSegUndo (this_sep, entityID);
2304   if (this_sep->choice != 2 || this_sep->data.ptrvalue == NULL)
2305   {
2306     return;
2307   }
2308 
2309   target_bssp = (BioseqSetPtr) this_sep->data.ptrvalue;
2310 
2311   if (parent_bssp != NULL
2312       && parent_bssp->_class == BioseqseqSet_class_nuc_prot
2313       && !SetContainsProteins (target_bssp))
2314   {
2315     seg_list = target_bssp->seq_set;
2316     target_bssp->seq_set = NULL;
2317 
2318     protein_list = parent_bssp->seq_set->next;
2319     parent_bssp->seq_set->next = NULL;
2320 
2321     /* parent_bssp->seq_set is this_sep */
2322     /* we've already moved everything out of this_sep, so we can free it now */
2323     parent_bssp->seq_set = SeqEntryFree (parent_bssp->seq_set);
2324     this_sep = NULL;
2325     target_bssp = NULL;
2326 
2327     if (IS_Bioseq_set (seg_list))
2328     {
2329       this_sep = seg_list;
2330       target_bssp = seg_list->data.ptrvalue;
2331       seg_list = target_bssp->seq_set;
2332       target_bssp->seq_set = NULL;
2333       this_sep = SeqEntryFree (this_sep);
2334       target_bssp = NULL;
2335     }
2336 
2337     for (seg_sep = seg_list; seg_sep != NULL; seg_sep = next_seg)
2338     {
2339       next_seg = seg_sep->next;
2340       if (!IS_Bioseq (seg_sep) || seg_sep->data.ptrvalue == NULL)
2341       {
2342         seg_bssp = (BioseqSetPtr) seg_sep->data.ptrvalue;
2343         continue;
2344       }
2345       seg_bsp = (BioseqPtr) seg_sep->data.ptrvalue;
2346       /* get the proteins from the parent set that go with this segment */
2347       this_prot_list = NULL;
2348       last_this = NULL;
2349       prot_sep = protein_list;
2350       prev_prot_sep = NULL;
2351       while (prot_sep != NULL)
2352       {
2353         next_prot_sep = prot_sep->next;
2354         if (ProteinUsedForThisSegmentInThisAnnotList (seg_sep, prot_sep, parent_bssp->annot)
2355             || ProteinUsedForThisSegmentInThisAnnotList (seg_sep, prot_sep, seg_bsp->annot))
2356         {
2357           /* remove from total list */
2358           if (prev_prot_sep == NULL)
2359           {
2360             protein_list = prot_sep->next;
2361           }
2362           else
2363           {
2364             prev_prot_sep->next = prot_sep->next;
2365           }
2366           prot_sep->next = NULL;
2367 
2368           /* add to list for this nuc-prot set */
2369           if (last_this == NULL)
2370           {
2371             this_prot_list = prot_sep;
2372           }
2373           else
2374           {
2375             last_this->next = prot_sep;
2376           }
2377           last_this = prot_sep;
2378         }
2379         else
2380         {
2381           prev_prot_sep = prot_sep;
2382         }
2383         prot_sep = next_prot_sep;
2384       }
2385 
2386       if (this_prot_list != NULL)
2387       {
2388         seg_nuc_prot = BioseqSetNew ();
2389         seg_nuc_prot->_class = BioseqseqSet_class_nuc_prot;
2390         seg_nuc_prot->seq_set = SeqEntryNew ();
2391         seg_nuc_prot->seq_set->choice = 1;
2392         seg_nuc_prot->seq_set->data.ptrvalue = seg_bsp;
2393         seg_nuc_prot->seq_set->next = this_prot_list;
2394         seg_sep->choice = 2;
2395         seg_sep->data.ptrvalue = seg_nuc_prot;
2396       }
2397     }
2398     parent_bssp->_class = BioseqseqSet_class_genbank;
2399     parent_bssp->seq_set = seg_list;
2400   }
2401 
2402   if (protein_list != NULL && parent_bssp != NULL)
2403   {
2404     seg_sep = parent_bssp->seq_set;
2405     while (seg_sep != NULL && seg_sep->next != NULL)
2406     {
2407       seg_sep = seg_sep->next;
2408     }
2409     if (seg_sep == NULL)
2410     {
2411       parent_bssp->seq_set = protein_list;
2412     }
2413     else
2414     {
2415       seg_sep->next = protein_list;
2416     }
2417   }
2418 
2419   /* if we have just put a genbank set inside another genbank set, move the nuc-prot sets
2420    * up. */
2421   RemoveIntermediateGenBankWrapper (parent_bssp);
2422 }
2423 
2424 static void
RemoveOneUnsegmentedSet(SeqEntryPtr this_sep,BioseqSetPtr target_bssp,BioseqSetPtr parent_bssp)2425 RemoveOneUnsegmentedSet
2426 (SeqEntryPtr  this_sep,
2427  BioseqSetPtr target_bssp,
2428  BioseqSetPtr parent_bssp)
2429 {
2430   SeqEntryPtr last_sep, prev_sep, target_sep;
2431 
2432   if (this_sep == NULL || target_bssp == NULL || parent_bssp == NULL)
2433   {
2434     return;
2435   }
2436 
2437   /* find last seqentry in target */
2438   last_sep = target_bssp->seq_set;
2439   while (last_sep != NULL && last_sep->next != NULL)
2440   {
2441     last_sep = last_sep->next;
2442   }
2443 
2444   /* find target in parent set, put seqentries in its place */
2445   prev_sep = NULL;
2446   target_sep = parent_bssp->seq_set;
2447   while (target_sep != this_sep)
2448   {
2449     prev_sep = target_sep;
2450     target_sep = target_sep->next;
2451   }
2452   if (last_sep != NULL)
2453   {
2454     if (prev_sep == NULL)
2455     {
2456       parent_bssp->seq_set = target_bssp->seq_set;
2457     }
2458     else
2459     {
2460       prev_sep->next = target_bssp->seq_set;
2461     }
2462     last_sep->next = this_sep->next;
2463   }
2464   this_sep->next = NULL;
2465   target_bssp->seq_set = NULL;
2466   SeqEntryFree (this_sep);
2467 }
2468 
2469 /* This function will remove a set and move the sequences in the set
2470  * to the parent set.
2471  */
RemoveSet(Pointer data)2472 static Int2 LIBCALLBACK RemoveSet (Pointer data)
2473 
2474 {
2475   ObjMgrDataPtr     omdptop;
2476   ObjMgrData        omdata;
2477   OMProcControlPtr  ompcp;
2478   Uint2             parenttype, top_parenttype;
2479   Pointer           parentptr, top_parentptr;
2480   SeqEntryPtr       top_sep, this_sep;
2481   BioseqSetPtr      target_bssp, parent_bssp;
2482   ValNodePtr        titles;
2483 
2484   ompcp = (OMProcControlPtr) data;
2485   if (ompcp == NULL
2486       || ompcp->input_itemtype != OBJ_BIOSEQSET
2487       || ompcp->input_data == NULL)
2488   {
2489     return OM_MSG_RET_ERROR;
2490   }
2491 
2492   top_sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
2493   if (top_sep == NULL) return OM_MSG_RET_ERROR;
2494   this_sep = SeqMgrGetSeqEntryForData (ompcp->input_data);
2495   GetSeqEntryParent (this_sep, &parentptr, &parenttype);
2496 
2497   if (parenttype != OBJ_BIOSEQSET || parentptr == NULL)
2498   {
2499 	Message (MSG_ERROR, "Can't remove top set!");
2500     return OM_MSG_RET_ERROR;
2501   }
2502 
2503   SaveSeqEntryObjMgrData (top_sep, &omdptop, &omdata);
2504   GetSeqEntryParent (top_sep, &top_parentptr, &top_parenttype);
2505 
2506   target_bssp = (BioseqSetPtr) ompcp->input_data;
2507   parent_bssp = (BioseqSetPtr) parentptr;
2508 
2509   if (parent_bssp->_class == BioseqseqSet_class_not_set
2510       || parent_bssp->_class == BioseqseqSet_class_segset
2511       || parent_bssp->_class == BioseqseqSet_class_parts)
2512   {
2513     Message (MSG_ERROR, "Can't move sequences up into parent");
2514     return OM_MSG_RET_ERROR;
2515   }
2516 
2517   if (target_bssp->_class == BioseqseqSet_class_not_set
2518       || target_bssp->_class == BioseqseqSet_class_nuc_prot
2519       || target_bssp->_class == BioseqseqSet_class_parts)
2520   {
2521     Message (MSG_ERROR, "Can't disassemble this set");
2522     return OM_MSG_RET_ERROR;
2523   }
2524 
2525   if (target_bssp->_class == BioseqseqSet_class_segset)
2526   {
2527     RemoveOneSegSet (this_sep, parent_bssp, target_bssp, ompcp->input_entityID);
2528     /* propagate the descriptors on the set to the sequences in the set */
2529     SetDescriptorPropagate (parent_bssp);
2530     DoFixupLocus (top_sep);
2531     DoFixupSegSet (top_sep);
2532   }
2533   else if (parent_bssp->_class == BioseqseqSet_class_nuc_prot
2534             && ! SetContainsProteins (target_bssp))
2535   {
2536     Message (MSG_ERROR, "Can't move sequences up into parent");
2537     return OM_MSG_RET_ERROR;
2538   }
2539   else
2540   {
2541     /* first, remove set title if any */
2542     titles = ValNodeExtractList (&(target_bssp->descr), Seq_descr_title);
2543     titles = SeqDescrFree (titles);
2544     /* propagate the descriptors on the set to the sequences in the set */
2545     SetDescriptorPropagate (target_bssp);
2546 
2547     RemoveOneUnsegmentedSet (this_sep, target_bssp, parent_bssp);
2548   }
2549 
2550   SeqMgrLinkSeqEntry (top_sep, top_parenttype, top_parentptr);
2551 
2552   SeqMgrClearFeatureIndexes (ompcp->input_entityID, NULL);
2553   SeqMgrIndexFeatures (ompcp->input_entityID, NULL);
2554 
2555   RestoreSeqEntryObjMgrData (top_sep, omdptop, &omdata);
2556 
2557   SeqMgrClearFeatureIndexes (ompcp->input_entityID, NULL);
2558   SeqMgrIndexFeatures (ompcp->input_entityID, NULL);
2559 
2560   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
2561   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
2562 
2563   ForceCleanupEntityID (ompcp->input_entityID);
2564 
2565   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
2566   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
2567 
2568   return OM_MSG_RET_DONE;
2569 }
2570 
2571 static Boolean
RemoveSetsInNucProtSet(BioseqSetPtr parent_bssp,Uint2 entityID)2572 RemoveSetsInNucProtSet
2573 (BioseqSetPtr parent_bssp,
2574  Uint2        entityID)
2575 {
2576   Boolean      rval = FALSE;
2577   SeqEntryPtr  this_sep;
2578   BioseqSetPtr target_bssp;
2579 
2580   if (parent_bssp == NULL || parent_bssp->_class != BioseqseqSet_class_nuc_prot)
2581   {
2582     return FALSE;
2583   }
2584 
2585   this_sep = parent_bssp->seq_set;
2586   if (this_sep != NULL
2587       && IS_Bioseq_set (this_sep)
2588       && this_sep->data.ptrvalue != NULL)
2589   {
2590     target_bssp = (BioseqSetPtr) this_sep->data.ptrvalue;
2591     if (target_bssp->_class == BioseqseqSet_class_segset)
2592     {
2593       RemoveOneSegSet (this_sep, parent_bssp, target_bssp, entityID);
2594       /* propagate the descriptors on the set to the sequences in the set */
2595       SetDescriptorPropagate (parent_bssp);
2596       rval = TRUE;
2597     }
2598   }
2599   return rval;
2600 }
2601 
2602 
RemoveSetsInBioseqSet(BioseqSetPtr parent_bssp,Uint2 entityID)2603 static Int2 LIBCALLBACK RemoveSetsInBioseqSet (BioseqSetPtr parent_bssp, Uint2 entityID)
2604 {
2605   ObjMgrDataPtr     omdptop;
2606   ObjMgrData        omdata;
2607   Uint2             top_parenttype;
2608   Pointer           top_parentptr;
2609   SeqEntryPtr       top_sep, this_sep, next_sep;
2610   BioseqSetPtr      target_bssp;
2611   Boolean           need_locus_fixup = FALSE;
2612   SeqDescrPtr       titles;
2613 
2614   if (parent_bssp == NULL) {
2615     return OM_MSG_RET_ERROR;
2616   }
2617 
2618   top_sep = GetTopSeqEntryForEntityID (entityID);
2619   if (top_sep == NULL) return OM_MSG_RET_ERROR;
2620   SaveSeqEntryObjMgrData (top_sep, &omdptop, &omdata);
2621   GetSeqEntryParent (top_sep, &top_parentptr, &top_parenttype);
2622 
2623   if (parent_bssp->_class == BioseqseqSet_class_not_set
2624       || parent_bssp->_class == BioseqseqSet_class_segset
2625       || parent_bssp->_class == BioseqseqSet_class_parts)
2626   {
2627     Message (MSG_ERROR, "Can't move sequences up into parent");
2628     return OM_MSG_RET_ERROR;
2629   }
2630   else if (parent_bssp->_class == BioseqseqSet_class_nuc_prot)
2631   {
2632     if (! RemoveSetsInNucProtSet (parent_bssp, entityID))
2633     {
2634       Message (MSG_ERROR, "Can't move sequences up into parent");
2635       return OM_MSG_RET_ERROR;
2636     }
2637     else
2638     {
2639       need_locus_fixup = TRUE;
2640     }
2641   }
2642   else
2643   {
2644     for (this_sep = parent_bssp->seq_set; this_sep != NULL; this_sep = next_sep)
2645     {
2646       next_sep = this_sep->next;
2647       if (!IS_Bioseq_set (this_sep) || this_sep->data.ptrvalue == NULL)
2648       {
2649         continue;
2650       }
2651       target_bssp = (BioseqSetPtr) this_sep->data.ptrvalue;
2652       if (target_bssp->_class == BioseqseqSet_class_nuc_prot)
2653       {
2654         need_locus_fixup |= RemoveSetsInNucProtSet (target_bssp, entityID);
2655       }
2656       else if (target_bssp->_class == BioseqseqSet_class_segset)
2657       {
2658         RemoveOneSegSet (this_sep, parent_bssp, target_bssp, entityID);
2659       }
2660       else if (target_bssp->_class != BioseqseqSet_class_not_set
2661                && target_bssp->_class != BioseqseqSet_class_parts)
2662       {
2663         /* first, remove set title if any */
2664         titles = ValNodeExtractList (&(target_bssp->descr), Seq_descr_title);
2665         titles = SeqDescrFree (titles);
2666 
2667         /* propagate the descriptors on the set to the sequences in the set */
2668         SetDescriptorPropagate (target_bssp);
2669 
2670         RemoveOneUnsegmentedSet (this_sep, target_bssp, parent_bssp);
2671       }
2672     }
2673   }
2674 
2675   if (need_locus_fixup)
2676   {
2677     DoFixupLocus (top_sep);
2678     DoFixupSegSet (top_sep);
2679   }
2680 
2681   SeqMgrLinkSeqEntry (top_sep, top_parenttype, top_parentptr);
2682 
2683   SeqMgrClearFeatureIndexes (entityID, NULL);
2684   SeqMgrIndexFeatures (entityID, NULL);
2685 
2686   RestoreSeqEntryObjMgrData (top_sep, omdptop, &omdata);
2687 
2688   SeqMgrClearFeatureIndexes (entityID, NULL);
2689   SeqMgrIndexFeatures (entityID, NULL);
2690 
2691   ObjMgrSetDirtyFlag (entityID, TRUE);
2692   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
2693 
2694   ForceCleanupEntityID (entityID);
2695 
2696   ObjMgrSetDirtyFlag (entityID, TRUE);
2697   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
2698 
2699   return OM_MSG_RET_DONE;
2700 }
2701 
RemoveSetsInSelectedSet(Pointer data)2702 static Int2 LIBCALLBACK RemoveSetsInSelectedSet (Pointer data)
2703 {
2704   OMProcControlPtr  ompcp;
2705 
2706   ompcp = (OMProcControlPtr) data;
2707   if (ompcp == NULL
2708       || ompcp->input_itemtype != OBJ_BIOSEQSET
2709       || ompcp->input_data == NULL)
2710   {
2711     return OM_MSG_RET_ERROR;
2712   }
2713 
2714   return RemoveSetsInBioseqSet((BioseqSetPtr) ompcp->input_data, ompcp->input_entityID);
2715 
2716 }
2717 
2718 
RemoveSetsInSetMenuItem(IteM i)2719 extern void RemoveSetsInSetMenuItem (IteM i)
2720 {
2721   BaseFormPtr   bfp;
2722   BioseqSetPtr  bssp;
2723   SeqEntryPtr   sep;
2724 
2725 #ifdef WIN_MAC
2726   bfp = currentFormDataPtr;
2727 #else
2728   bfp = GetObjectExtra (i);
2729 #endif
2730   if (bfp == NULL) return;
2731 
2732   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2733   if (sep == NULL || !IS_Bioseq_set (sep)) {
2734     Message (MSG_ERROR, "This record does not have a top-levelset!");
2735   } else {
2736     bssp = FindTopLevelSetForDesktopFunction((BioseqSetPtr) sep->data.ptrvalue);
2737     RemoveSetsInBioseqSet(bssp, bfp->input_entityID);
2738   }
2739 }
2740 
2741 
ApplySetTypeToSeqEntry(SeqEntryPtr sep,Uint1 new_class,Boolean is_top)2742 NLM_EXTERN void ApplySetTypeToSeqEntry (SeqEntryPtr sep, Uint1 new_class, Boolean is_top)
2743 {
2744   BioseqSetPtr bssp;
2745 
2746   if (sep == NULL || !IS_Bioseq_set (sep)
2747       || (bssp = (BioseqSetPtr) sep->data.ptrvalue) == NULL
2748       || bssp->_class == BioseqseqSet_class_nuc_prot
2749       || bssp->_class == BioseqseqSet_class_segset) {
2750     return;
2751   }
2752 
2753   if (is_top) {
2754     for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
2755       ApplySetTypeToSeqEntry (sep, new_class, FALSE);
2756     }
2757   } else {
2758     bssp->_class = new_class;
2759   }
2760 }
2761 
2762 
ApplySetTypeDesktop(Pointer data)2763 static Int2 LIBCALLBACK ApplySetTypeDesktop (Pointer data)
2764 {
2765   OMProcControlPtr  ompcp;
2766 
2767   ompcp = (OMProcControlPtr) data;
2768   if (ompcp == NULL
2769       || ompcp->input_itemtype != OBJ_BIOSEQSET
2770       || ompcp->input_data == NULL)
2771   {
2772     return OM_MSG_RET_ERROR;
2773   }
2774   ApplySetTypeToInnerSets (ompcp->input_data, ompcp->input_entityID);
2775   return OM_MSG_RET_DONE;
2776 }
2777 
2778 
NoMoreSegGapForOneAlignment(SeqAlignPtr sap,Pointer userdata)2779 static void NoMoreSegGapForOneAlignment (SeqAlignPtr sap, Pointer userdata)
2780 {
2781   SeqAlignPtr       salp;
2782 
2783   salp = sap;
2784   while (salp != NULL)
2785   {
2786     if (salp->saip != NULL)
2787     {
2788        SeqAlignIndexFree(salp->saip);
2789        salp->saip = NULL;
2790     } else {
2791        AlnMgr2IndexSingleChildSeqAlign(salp); /* make sure it's dense-seg */
2792        SeqAlignIndexFree(salp->saip);
2793        salp->saip = NULL;
2794     }
2795     CleanUpSegGap(salp);
2796     AlnMgr2IndexSingleChildSeqAlign(salp);
2797     salp = salp->next;
2798   }
2799 }
2800 
2801 
NoMoreSegGap(Pointer data)2802 static Int2 LIBCALLBACK NoMoreSegGap (Pointer data)
2803 {
2804   OMProcControlPtr  ompcp;
2805   SeqAlignPtr       sap;
2806   SeqAnnotPtr       sanp;
2807 
2808   ompcp = (OMProcControlPtr) data;
2809   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
2810   switch (ompcp->input_itemtype) {
2811     case OBJ_SEQALIGN :
2812       sap = (SeqAlignPtr) ompcp->input_data;
2813       if (sap == NULL)
2814       {
2815         return OM_MSG_RET_ERROR;
2816       }
2817       else
2818       {
2819         NoMoreSegGapForOneAlignment (sap, NULL);
2820       }
2821       break;
2822     case OBJ_SEQANNOT :
2823       sanp = (SeqAnnotPtr) ompcp->input_data;
2824       if (sanp->type != 2)
2825       {
2826         return OM_MSG_RET_ERROR;
2827       }
2828       else if ((sap = (SeqAlignPtr)(sanp->data)) == NULL)
2829       {
2830         return OM_MSG_RET_ERROR;
2831       }
2832       else
2833       {
2834         NoMoreSegGapForOneAlignment (sap, NULL);
2835       }
2836       break;
2837     case OBJ_BIOSEQ :
2838       VisitAlignmentsOnBsp (ompcp->input_data, NULL, NoMoreSegGapForOneAlignment);
2839       break;
2840     case OBJ_BIOSEQSET :
2841       VisitAlignmentsInSet (ompcp->input_data, NULL, NoMoreSegGapForOneAlignment);
2842       break;
2843     case 0 :
2844       return OM_MSG_RET_ERROR;
2845       break;
2846     default :
2847       return OM_MSG_RET_ERROR;
2848       break;
2849   }
2850   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
2851   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
2852   return OM_MSG_RET_DONE;
2853 }
2854 
2855 
GetRidOfSegGapMenuItem(IteM i)2856 extern void GetRidOfSegGapMenuItem (IteM i)
2857 {
2858   BaseFormPtr   bfp;
2859   SeqEntryPtr   sep;
2860 
2861 #ifdef WIN_MAC
2862   bfp = currentFormDataPtr;
2863 #else
2864   bfp = GetObjectExtra (i);
2865 #endif
2866   if (bfp == NULL) return;
2867 
2868   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2869   VisitAlignmentsInSep (sep, NULL, NoMoreSegGapForOneAlignment);
2870   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2871   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2872 }
2873 
2874 
SqnSeqAlignDeleteInSeqEntryCallBack(SeqEntryPtr sep,Pointer mydata,Int4 index,Int2 indent)2875 static void SqnSeqAlignDeleteInSeqEntryCallBack (SeqEntryPtr sep, Pointer mydata,
2876                                           Int4 index, Int2 indent)
2877 {
2878   BioseqPtr          bsp;
2879   BioseqSetPtr       bssp;
2880   SeqAnnotPtr        sap,
2881                      pre;
2882   BoolPtr            dirtyp;
2883 
2884   if (sep != NULL && sep->data.ptrvalue && mydata != NULL) {
2885      dirtyp = (BoolPtr)mydata;
2886      if (IS_Bioseq(sep)) {
2887         bsp = (BioseqPtr) sep->data.ptrvalue;
2888         if (bsp!=NULL) {
2889            sap=bsp->annot;
2890            pre=NULL;
2891            while (sap) {
2892               if (sap->type == 2) {
2893                  if (pre==NULL) {
2894                     bsp->annot = sap->next;
2895                     sap->next=NULL;
2896                     sap = SeqAnnotFree (sap);
2897                     if (bsp->annot)
2898                        sap=bsp->annot->next;
2899                  }
2900                  else {
2901                     pre=sap->next;
2902                     sap->next=NULL;
2903                     sap = SeqAnnotFree (sap);
2904                     if (pre)
2905                        sap=pre->next;
2906                  }
2907                  *dirtyp=TRUE;
2908               }
2909               else {
2910                  pre=sap;
2911                  sap=sap->next;
2912               }
2913            }
2914         }
2915      }
2916      else if(IS_Bioseq_set(sep)) {
2917         bssp = (BioseqSetPtr)sep->data.ptrvalue;
2918         if (bssp!=NULL) {
2919            sap=bssp->annot;
2920            pre=NULL;
2921            while (sap) {
2922               if (sap->type == 2) {
2923                  if (pre==NULL) {
2924                     bssp->annot = sap->next;
2925                     sap->next=NULL;
2926                     sap = SeqAnnotFree (sap);
2927                     if (bssp->annot)
2928                        sap=bssp->annot->next;
2929                  }
2930                  else {
2931                     pre=sap->next;
2932                     sap->next=NULL;
2933                     sap = SeqAnnotFree (sap);
2934                     if (pre)
2935                        sap=pre->next;
2936                  }
2937                  *dirtyp=TRUE;
2938               }
2939               else {
2940                  pre=sap;
2941                  sap=sap->next;
2942               }
2943            }
2944         }
2945      }
2946   }
2947 }
2948 
2949 /* This function creates one SeqAnnot for each alignment in a chain of
2950  * alignments, breaking the chain for each alignment.
2951  * This is used to create the separate alignment annotations for a
2952  * discontiguous set of alignments, especially one created for a set
2953  * that contains delta sequences.
2954  */
2955 static void
CreateSeqAnnotsForDiscontiguousAlignments(SeqAlignPtr salp_mult,Uint2 entityID,BioseqSetPtr set_for_alignment)2956 CreateSeqAnnotsForDiscontiguousAlignments
2957 (SeqAlignPtr  salp_mult,
2958  Uint2        entityID,
2959  BioseqSetPtr set_for_alignment)
2960 {
2961   SeqAlignPtr       salp, salp_next;
2962   SeqAnnotPtr       sap;
2963   SeqEntryPtr       sep;
2964   SeqAnnotPtr PNTR  sapp = NULL;
2965   BioseqSetPtr      bssp;
2966   BioseqPtr         bsp;
2967   SeqAnnotPtr       curr;
2968 
2969   if (salp_mult == NULL)
2970   {
2971     return;
2972   }
2973   for (salp = salp_mult; salp != NULL; salp = salp_next)
2974   {
2975     salp_next = salp->next;
2976     salp->next = NULL;
2977     sap = SeqAnnotForSeqAlign(salp);
2978 
2979     if (sap != NULL) {
2980       if (set_for_alignment == NULL)
2981       {
2982         sep = GetTopSeqEntryForEntityID (entityID);
2983         if (sep != NULL && sep->data.ptrvalue != NULL) {
2984           sapp = NULL;
2985           if (IS_Bioseq (sep)) {
2986             bsp = (BioseqPtr) sep->data.ptrvalue;
2987             sapp = &(bsp->annot);
2988           } else if (IS_Bioseq_set (sep)) {
2989             bssp = (BioseqSetPtr) sep->data.ptrvalue;
2990             sapp = &(bssp->annot);
2991           }
2992         }
2993       }
2994       else
2995       {
2996         sapp = &(set_for_alignment->annot);
2997       }
2998 
2999       if (sapp != NULL) {
3000         if (*sapp != NULL) {
3001           curr = *sapp;
3002           while (curr->next != NULL) {
3003             curr = curr->next;
3004           }
3005           curr->next = sap;
3006         } else {
3007           *sapp = sap;
3008         }
3009       }
3010     }
3011   }
3012 }
3013 
3014 
UpdateSeqAlignForSeqEntry(SeqEntryPtr sep)3015 static Int2 LIBCALLBACK UpdateSeqAlignForSeqEntry (SeqEntryPtr sep)
3016 
3017 {
3018   Char              path [PATH_MAX];
3019   FILE              *fp;
3020   SeqAlignPtr       salp=NULL,
3021                     salpnew;
3022   SeqEntryPtr       sepnew=NULL;
3023   Uint2             entityID,
3024                     itemID;
3025   MsgAnswer         ans;
3026   Boolean           ok = TRUE,
3027                     dirty = FALSE;
3028   TSequenceInfoPtr  sequence_info;
3029   ReadBufferData    rbd;
3030   TErrorInfoPtr     error_list;
3031   TAlignmentFilePtr afp;
3032   Uint1             moltype;
3033   ErrSev            sev;
3034   SeqEntryPtr       scope;
3035   SeqAlignPtr       salp_copy;
3036   BioseqSetPtr      bssp = NULL;
3037 
3038   if (sep==NULL)
3039      return OM_MSG_RET_ERROR;
3040   entityID = ObjMgrGetEntityIDForChoice (sep);
3041   if (entityID < 1)
3042      return OM_MSG_RET_ERROR;
3043 
3044   if (IS_Bioseq_set (sep)) {
3045     bssp = sep->data.ptrvalue;
3046   }
3047 
3048   if (GetInputFileName (path, sizeof (path), NULL, "TEXT")) {
3049     fp = FileOpen (path, "r");
3050     if (fp != NULL) {
3051       sequence_info = GetAlignmentOptions (&moltype, NULL);
3052       if (sequence_info == NULL) return OM_MSG_RET_ERROR;
3053       error_list = NULL;
3054 
3055       rbd.fp = fp;
3056       rbd.current_data = NULL;
3057       afp = ReadAlignmentFile ( AbstractReadFunction,
3058                                 (Pointer) &rbd,
3059                                 AbstractReportError,
3060                                 (Pointer) &error_list,
3061                                 sequence_info);
3062       if (afp != NULL)
3063       {
3064         SeqEntrySetScope (sep);
3065         if (CorrectAlignmentIDs (afp, moltype))
3066         {
3067           sepnew = MakeSequinDataFromAlignmentEx (afp, moltype, TRUE);
3068         }
3069       }
3070       ProduceAlignmentNotes (afp, error_list);
3071       ErrorInfoFree (error_list);
3072       SequenceInfoFree (sequence_info);
3073       AlignmentFileFree (afp);
3074       Update ();
3075     }
3076   }
3077   if (sepnew)
3078   {
3079     salpnew = (SeqAlignPtr) FindSeqAlignInSeqEntry (sepnew, OBJ_SEQALIGN);
3080     if (salpnew) {
3081       sev = ErrSetMessageLevel (SEV_FATAL);
3082 
3083       scope = SeqEntrySetScope (NULL);
3084       /* adjust the start positions for the sequences read in from the alignments. */
3085       CalculateAlignmentOffsets (sepnew, sep);
3086       /* ValidateSeqAlignandACCInSeqEntry will readjust the start positions for
3087        * the alignments for far pointer sequences.
3088        */
3089       SeqEntrySetScope (scope);
3090       ok = ValidateSeqAlignandACCInSeqEntry (sepnew, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE);
3091 
3092       ErrSetMessageLevel (sev);
3093 
3094       if (ok) {
3095         AlnMgr2IndexSeqAlignEx(salpnew, FALSE);
3096         ok = CheckAlignmentSequenceLengths (salpnew);
3097       }
3098 
3099       if (ok) {
3100         /* if there is already an alignment, ask if the user wants to remove the old
3101          * one before adding the new alignment.
3102          */
3103         salp = (SeqAlignPtr) FindSeqAlignInSeqEntry (sep, OBJ_SEQALIGN);
3104         if (salp)
3105         {
3106           ans = Message (MSG_OKC, "Do you wish to replace (OK) or add (Cancel) the alignment in your SeqEntry?");
3107           if (ans == ANS_OK)
3108           {
3109             SeqEntryExplore (sep, &dirty, SqnSeqAlignDeleteInSeqEntryCallBack);
3110           }
3111         }
3112 
3113         /* make a copy of the alignment in sepnew - the alignment in sepnew will
3114          * be freed when sepnew is freed.
3115          */
3116         salp_copy = (SeqAlignPtr) AsnIoMemCopy (salpnew, (AsnReadFunc) SeqAlignAsnRead,
3117                                                        (AsnWriteFunc) SeqAlignAsnWrite);
3118         /* the copy function doesn't copy the index, so the alignment must be
3119          * indexed now.
3120          */
3121         AlnMgr2IndexSeqAlignEx(salp_copy, FALSE);
3122         /* break the alignment at gaps, if the set contains any delta sequences */
3123         salp_copy = MakeDiscontiguousAlignments (salp_copy);
3124 
3125         /* break the chain of alignments and create separate SeqAnnots for each one */
3126         CreateSeqAnnotsForDiscontiguousAlignments (salp_copy, entityID, bssp);
3127         ObjMgrSetDirtyFlag (entityID, TRUE);
3128         itemID = GetItemIDGivenPointer (entityID, OBJ_SEQENTRY, (Pointer) sep);
3129         ObjMgrSendMsg (OM_MSG_UPDATE, entityID, itemID, OBJ_SEQENTRY);
3130       }
3131     }
3132     ObjMgrFree (OBJ_SEQENTRY, (Pointer)sepnew);
3133     sepnew=NULL;
3134   }
3135   return OM_MSG_RET_OK;
3136 }
3137 
NewUpdateSeqAlign(Pointer data)3138 static Int2 LIBCALLBACK NewUpdateSeqAlign (Pointer data)
3139 {
3140   OMProcControlPtr ompcp;
3141   SeqEntryPtr      sep = NULL;
3142   BioseqSetPtr     bssp;
3143   SeqSubmitPtr     ssp;
3144 
3145   ompcp = (OMProcControlPtr) data;
3146   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
3147 
3148   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
3149 
3150   switch(ompcp->input_itemtype)
3151     {
3152     case OBJ_BIOSEQ :
3153       sep = SeqMgrGetSeqEntryForData (ompcp->input_data);
3154       break;
3155     case OBJ_BIOSEQSET :
3156       sep = SeqMgrGetSeqEntryForData (ompcp->input_data);
3157       bssp = (BioseqSetPtr) ompcp->input_data;
3158       break;
3159     case OBJ_SEQENTRY :
3160       sep = ompcp->input_data;
3161       break;
3162     case OBJ_SEQSUB :
3163       ssp = ompcp->input_data;
3164       if(ssp->datatype==1)
3165          sep = (SeqEntryPtr)ssp->data;
3166       break;
3167     case 0 :
3168       return OM_MSG_RET_ERROR;
3169     default :
3170       return OM_MSG_RET_ERROR;
3171   }
3172   if (sep==NULL)
3173      return OM_MSG_RET_ERROR;
3174 
3175   return UpdateSeqAlignForSeqEntry (sep);
3176 
3177 }
3178 
UpdateSeqAlignMenuItem(IteM i)3179 extern void UpdateSeqAlignMenuItem (IteM i)
3180 {
3181   BaseFormPtr   bfp;
3182   BioseqSetPtr  bssp;
3183   SeqEntryPtr   sep;
3184 
3185 #ifdef WIN_MAC
3186   bfp = currentFormDataPtr;
3187 #else
3188   bfp = GetObjectExtra (i);
3189 #endif
3190   if (bfp == NULL) return;
3191 
3192   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3193   if (sep == NULL || !IS_Bioseq_set (sep)) {
3194     Message (MSG_ERROR, "This record does not have a top-levelset!");
3195   } else {
3196     bssp = FindTopLevelSetForDesktopFunction((BioseqSetPtr) sep->data.ptrvalue);
3197     sep = SeqMgrGetSeqEntryForData (bssp);
3198     UpdateSeqAlignForSeqEntry (sep);
3199   }
3200 }
3201 
3202 
DenseSegSwitchSeqPos(DenseSegPtr dsp)3203 static void DenseSegSwitchSeqPos (DenseSegPtr dsp)
3204 {
3205   SeqIdPtr sip, sip_next;
3206   Int4     tmp_start, i;
3207   Uint1    tmp_strand;
3208 
3209   if (dsp == NULL || dsp->dim != 2) {
3210     return;
3211   }
3212 
3213   /* switch the IDs */
3214   sip = dsp->ids;
3215   sip_next = dsp->ids->next;
3216   sip_next->next = sip;
3217   sip->next = NULL;
3218   dsp->ids = sip_next;
3219 
3220   /* switch the starts and strands*/
3221   for (i = 0; i < dsp->numseg; i++) {
3222     tmp_start = dsp->starts[(i * dsp->dim)];
3223     dsp->starts[(i * dsp->dim)] = dsp->starts[(i * dsp->dim) + 1];
3224     dsp->starts[(i * dsp->dim) + 1] = tmp_start;
3225   }
3226 
3227   if (dsp->strands != NULL) {
3228     for (i = 0; i < dsp->numseg; i++) {
3229       tmp_strand = dsp->strands[(i * dsp->dim)];
3230       dsp->strands[(i * dsp->dim)] = dsp->strands[(i * dsp->dim) + 1];
3231       dsp->strands[(i * dsp->dim) + 1] = tmp_strand;
3232     }
3233   }
3234 }
3235 
3236 
FindBioseqForSeqHist(SeqAlignPtr salp)3237 static BioseqPtr FindBioseqForSeqHist (SeqAlignPtr salp)
3238 {
3239   SeqIdPtr  sip;
3240   BioseqPtr bsp;
3241   DenseSegPtr dsp;
3242 
3243   if (salp == NULL || salp->dim != 2 || salp->segtype != SAS_DENSEG) {
3244     return NULL;
3245   }
3246 
3247   dsp = (DenseSegPtr) salp->segs;
3248 
3249   sip = dsp->ids->next;
3250 
3251   bsp = BioseqFind (sip);
3252   if (bsp == NULL) {
3253     /* if we find the bioseq here, need to switch the positions */
3254     sip = dsp->ids;
3255     bsp = BioseqFind (sip);
3256     if (bsp != NULL) {
3257       DenseSegSwitchSeqPos (dsp);
3258     }
3259   }
3260   return bsp;
3261 }
3262 
3263 
CorrectIDsForSeqHistAlign(TAlignmentFilePtr afp,SeqEntryPtr sep)3264 static SeqIdPtr CorrectIDsForSeqHistAlign (TAlignmentFilePtr afp, SeqEntryPtr sep)
3265 {
3266   SeqIdPtr sip;
3267   Boolean  need_switch = FALSE;
3268   char *tmp;
3269 
3270   if (afp == NULL || afp->num_sequences != 2) {
3271     return NULL;
3272   }
3273   if (StringNICmp (afp->ids[1], "acc", 3) == 0) {
3274     /* already have far pointer in place */
3275     sip = CreateSeqIdFromText (afp->ids[0], sep);
3276   } else if (StringNICmp (afp->ids[0], "acc", 3) == 0) {
3277     need_switch = TRUE;
3278     sip = CreateSeqIdFromText (afp->ids[1], sep);
3279   } else {
3280     /* first position should be primary */
3281     sip = CreateSeqIdFromText (afp->ids[0], sep);
3282     if (sip == NULL) {
3283       sip = CreateSeqIdFromText (afp->ids[1], sep);
3284       if (sip == NULL) {
3285         /* can't find match in record */
3286       } else {
3287         /* second position is primary, put acc on first position */
3288         need_switch = TRUE;
3289         tmp = malloc (StringLen (afp->ids[0]) + 4);
3290         sprintf (tmp, "acc%s", afp->ids[0]);
3291         free (afp->ids[0]);
3292         afp->ids[0] = tmp;
3293       }
3294     } else {
3295       tmp = malloc (StringLen (afp->ids[1]) + 4);
3296       sprintf (tmp, "acc%s", afp->ids[1]);
3297       free (afp->ids[1]);
3298       afp->ids[1] = tmp;
3299     }
3300   }
3301 
3302   if (sip != NULL) {
3303     if (need_switch) {
3304       /* note - not bothering to switch deflines and organism names because
3305        * we don't need them for the seq-hist assembly
3306        */
3307       tmp = afp->ids[0];
3308       afp->ids[0] = afp->ids[1];
3309       afp->ids[1] = tmp;
3310 
3311       tmp = afp->sequences[0];
3312       afp->sequences[0] = afp->sequences[1];
3313       afp->sequences[1] = tmp;
3314     }
3315   }
3316   return sip;
3317 }
3318 
3319 
IsIntervalGap(BioseqPtr bsp,Int4 start,Int4 stop)3320 static Boolean IsIntervalGap (BioseqPtr bsp, Int4 start, Int4 stop)
3321 {
3322   DeltaSeqPtr dsp;
3323   SeqLitPtr   litp;
3324   SeqLocPtr   loc;
3325   Int4        seq_offset = 0, len;
3326   Boolean     this_is_gap;
3327 
3328   if (bsp == NULL
3329       || bsp->repr != Seq_repr_delta
3330       || bsp->seq_ext_type != 4
3331       || start < 0
3332       || stop >= bsp->length)
3333   {
3334     return FALSE;
3335   }
3336 
3337   for (dsp = (DeltaSeqPtr) bsp->seq_ext;
3338        dsp != NULL && dsp->next != NULL && seq_offset < stop;
3339        dsp = dsp->next)
3340   {
3341     len = 0;
3342     this_is_gap = FALSE;
3343     if (dsp->choice == 1)
3344     {
3345       loc = (SeqLocPtr) dsp->data.ptrvalue;
3346       len = SeqLocLen (loc);
3347     }
3348     else if (dsp->choice == 2)
3349     {
3350       litp = (SeqLitPtr) dsp->data.ptrvalue;
3351       if (litp != NULL)
3352       {
3353         len = litp->length;
3354         if (IsDeltaSeqGap (dsp))
3355         {
3356           this_is_gap = TRUE;
3357         }
3358       }
3359     }
3360 
3361     if (seq_offset <= start && seq_offset + len >= stop)
3362     {
3363       return this_is_gap;
3364     }
3365     else if ((seq_offset <= start && seq_offset + len > start)
3366              || (seq_offset < stop && seq_offset + len > stop)
3367              || (seq_offset >= start && seq_offset + len <= stop))
3368     {
3369       if (!this_is_gap)
3370       {
3371         return FALSE;
3372       }
3373     }
3374     seq_offset += len;
3375   }
3376   return TRUE;
3377 }
3378 
3379 static Boolean
CollapseTwoGapSegments(DenseSegPtr dsp,Int4 seg_num_first,BioseqPtr PNTR bsparray)3380 CollapseTwoGapSegments
3381 (DenseSegPtr    dsp,
3382  Int4           seg_num_first,
3383  BioseqPtr PNTR bsparray)
3384 {
3385   Int4Ptr  newstarts;
3386   Int4Ptr  newlens;
3387   Uint1Ptr newstrands = NULL;
3388   Int4     row_num, seg_num;
3389 
3390   if (dsp == NULL || seg_num_first > dsp->numseg - 2)
3391   {
3392     return FALSE;
3393   }
3394 
3395   if (dsp->lens [seg_num_first] != dsp->lens [seg_num_first + 1])
3396   {
3397     return FALSE;
3398   }
3399 
3400   for (row_num = 0; row_num < dsp->dim; row_num++)
3401   {
3402     if (dsp->starts [seg_num_first * dsp->dim + row_num] != -1
3403         && dsp->starts [(seg_num_first + 1) * dsp->dim + row_num] != -1)
3404     {
3405       return FALSE;
3406     }
3407 
3408     /* segment must be over a gap for all rows not in gap */
3409     /* for the first segment */
3410     if (dsp->starts [seg_num_first * dsp->dim + row_num] != -1
3411         && ! IsIntervalGap (bsparray[row_num],
3412                             dsp->starts [seg_num_first * dsp->dim + row_num],
3413                             dsp->starts [seg_num_first * dsp->dim + row_num] + dsp->lens[seg_num_first]))
3414 
3415     {
3416       return FALSE;
3417     }
3418     /* and for the second segment */
3419     if (dsp->starts [(seg_num_first + 1) * dsp->dim + row_num] != -1
3420         && ! IsIntervalGap (bsparray[row_num],
3421                             dsp->starts [(seg_num_first + 1) * dsp->dim + row_num],
3422                             dsp->starts [(seg_num_first + 1) * dsp->dim + row_num] + dsp->lens[seg_num_first + 1]))
3423 
3424     {
3425       return FALSE;
3426     }
3427   }
3428 
3429   newstarts = (Int4Ptr) MemNew (sizeof (Int4) * dsp->dim * (dsp->numseg - 1));
3430   newlens = (Int4Ptr) MemNew (sizeof (Int4) * (dsp->numseg - 1));
3431   if (dsp->strands != NULL)
3432   {
3433     newstrands = (Uint1Ptr) MemNew (sizeof (Uint1) * dsp->dim * (dsp->numseg - 1));
3434   }
3435 
3436   /* copy the portion of the alignment before the segments to be collapsed */
3437   for (seg_num = 0; seg_num < seg_num_first; seg_num++)
3438   {
3439     for (row_num = 0; row_num < dsp->dim; row_num++)
3440     {
3441       newstarts [seg_num * dsp->dim + row_num] = dsp->starts [seg_num * dsp->dim + row_num];
3442       if (dsp->strands != NULL)
3443       {
3444         newstrands [seg_num * dsp->dim + row_num] = dsp->strands[seg_num * dsp->dim + row_num];
3445       }
3446     }
3447     newlens[seg_num] = dsp->lens[seg_num];
3448   }
3449 
3450   /* collapse the two segments */
3451   for (row_num = 0; row_num < dsp->dim; row_num++)
3452   {
3453     if (dsp->starts [seg_num * dsp->dim + row_num] == -1)
3454     {
3455       newstarts [seg_num * dsp->dim + row_num] = dsp->starts [(seg_num + 1) * dsp->dim + row_num];
3456       if (dsp->strands != NULL)
3457       {
3458         newstrands [seg_num * dsp->dim + row_num] = dsp->strands [(seg_num + 1) * dsp->dim + row_num];
3459       }
3460     }
3461     else
3462     {
3463       newstarts [seg_num * dsp->dim + row_num] = dsp->starts [seg_num * dsp->dim + row_num];
3464       if (dsp->strands != NULL)
3465       {
3466         newstrands [seg_num * dsp->dim + row_num] = dsp->strands [seg_num * dsp->dim + row_num];
3467       }
3468     }
3469   }
3470   newlens [seg_num] = dsp->lens [seg_num];
3471   seg_num++;
3472 
3473   /* copy the remaining segments after the collapsed pair */
3474   while (seg_num < dsp->numseg - 1)
3475   {
3476     for (row_num = 0; row_num < dsp->dim; row_num++)
3477     {
3478       newstarts [seg_num * dsp->dim + row_num] = dsp->starts [(seg_num + 1) * dsp->dim + row_num];
3479       if (dsp->strands != NULL)
3480       {
3481         newstrands [seg_num * dsp->dim + row_num] = dsp->strands[(seg_num + 1) * dsp->dim + row_num];
3482       }
3483     }
3484     newlens[seg_num] = dsp->lens[(seg_num + 1)];
3485     seg_num++;
3486   }
3487 
3488   /* replace the starts, strands, lens, and numseg in dsp */
3489   dsp->starts = MemFree (dsp->starts);
3490   dsp->starts = newstarts;
3491   dsp->strands = MemFree (dsp->strands);
3492   dsp->strands = newstrands;
3493   dsp->lens = MemFree (dsp->lens);
3494   dsp->lens = newlens;
3495   dsp->numseg--;
3496   return TRUE;
3497 }
3498 
ConsolidateSegmentsOverKnownLengthGaps(SeqAlignPtr salp)3499 extern void ConsolidateSegmentsOverKnownLengthGaps (SeqAlignPtr salp)
3500 {
3501   DenseSegPtr    dsp;
3502   SeqIdPtr       sip;
3503   BioseqPtr PNTR bsparray;
3504   Int4           row_num, seg_num;
3505 
3506   if (salp == NULL || salp->segtype != SAS_DENSEG || salp->segs == NULL)
3507   {
3508     return;
3509   }
3510 
3511   if (salp->saip != NULL)
3512   {
3513     SeqAlignIndexFree(salp->saip);
3514     salp->saip = NULL;
3515   }
3516 
3517   dsp = (DenseSegPtr) salp->segs;
3518 
3519   bsparray = (BioseqPtr PNTR) MemNew (sizeof (BioseqPtr) * dsp->dim);
3520 
3521 
3522   for (sip = dsp->ids, row_num = 0;
3523        sip != NULL && row_num < dsp->dim;
3524        sip = sip->next, row_num++)
3525   {
3526     bsparray [row_num] = BioseqFind (sip);
3527   }
3528 
3529   seg_num = 0;
3530   while (seg_num < dsp->numseg - 1)
3531   {
3532     if (!CollapseTwoGapSegments (dsp, seg_num, bsparray))
3533     {
3534       seg_num++;
3535     }
3536   }
3537 
3538   AlnMgr2IndexSeqAlignEx(salp, FALSE);
3539   bsparray = MemFree (bsparray);
3540 }
3541 
ConsolidateGapGaps(Pointer data)3542 static Int2 LIBCALLBACK ConsolidateGapGaps (Pointer data)
3543 
3544 {
3545   OMProcControlPtr  ompcp;
3546   SeqAlignPtr       salp=NULL;
3547   Uint2             entityID;
3548   SeqAnnotPtr       sanp_old;
3549 
3550   ompcp = (OMProcControlPtr) data;
3551   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
3552 
3553   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
3554 
3555   switch(ompcp->input_itemtype)
3556     {
3557     case OBJ_SEQALIGN :
3558       salp = (SeqAlignPtr) ompcp->input_data;
3559       break;
3560     case OBJ_SEQANNOT:
3561       sanp_old = (SeqAnnotPtr) ompcp->input_data;
3562       if (sanp_old->type == 2)
3563       {
3564         salp = sanp_old->data;
3565       }
3566       break;
3567     default :
3568       return OM_MSG_RET_ERROR;
3569   }
3570   if (salp==NULL)
3571      return OM_MSG_RET_ERROR;
3572   entityID = ompcp->input_entityID;
3573   if (entityID < 1)
3574      return OM_MSG_RET_ERROR;
3575 
3576   ConsolidateSegmentsOverKnownLengthGaps (salp);
3577 
3578   ObjMgrSetDirtyFlag (entityID, TRUE);
3579 
3580   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
3581 
3582   return OM_MSG_RET_OK;
3583 }
3584 
3585 
3586 /* NOTE - need to call DeleteMarkedObjects after calling this function */
FixOneAlignmentOverGaps(SeqAlignPtr salp,Uint2 entityID)3587 extern void FixOneAlignmentOverGaps (SeqAlignPtr salp, Uint2 entityID)
3588 {
3589   SeqAnnotPtr       sanp_old, sanp_new;
3590   SeqAlignPtr       salp_copy, salp_tmp;
3591   BioseqSetPtr      bssp = NULL;
3592 
3593   sanp_old = GetSeqAnnotForAlignment (salp);
3594   if (sanp_old == NULL)
3595   {
3596      return;
3597   }
3598 
3599   if (sanp_old->idx.parenttype == OBJ_BIOSEQSET)
3600   {
3601     bssp = (BioseqSetPtr) sanp_old->idx.parentptr;
3602   }
3603 
3604   /* make a copy of the alignment */
3605   salp_copy = (SeqAlignPtr) AsnIoMemCopy (salp, (AsnReadFunc) SeqAlignAsnRead,
3606                                                        (AsnWriteFunc) SeqAlignAsnWrite);
3607   /* the copy function doesn't copy the index, so the alignment must be
3608    * indexed now.
3609    */
3610   AlnMgr2IndexSeqAlignEx(salp_copy, FALSE);
3611   /* break the alignment at gaps, if the set contains any delta sequences */
3612   salp_copy = MakeDiscontiguousAlignments (salp_copy);
3613 
3614   for (salp_tmp = salp_copy; salp_tmp != NULL; salp_tmp = salp_tmp->next)
3615   {
3616      NoMoreSegGapForOneAlignment (salp_tmp, NULL);
3617   }
3618 
3619   /* break the chain of alignments and create separate SeqAnnots for each one */
3620   CreateSeqAnnotsForDiscontiguousAlignments (salp_copy, entityID, bssp);
3621 
3622   /* need to index the alignments before we can find the new alignment and remove the old */
3623   ObjMgrSetDirtyFlag (entityID, TRUE);
3624   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
3625 
3626   sanp_new = GetSeqAnnotForAlignment (salp_copy);
3627 
3628   if (sanp_new != NULL)
3629   {
3630     salp->idx.deleteme = TRUE;
3631   }
3632 }
3633 
FixAlignmentOverGaps(Pointer data)3634 static Int2 LIBCALLBACK FixAlignmentOverGaps (Pointer data)
3635 
3636 {
3637   OMProcControlPtr  ompcp;
3638   SeqAlignPtr       salp=NULL;
3639   Uint2             entityID;
3640   SeqAnnotPtr       sanp_old;
3641 
3642   ompcp = (OMProcControlPtr) data;
3643   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
3644 
3645   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
3646 
3647   switch(ompcp->input_itemtype)
3648     {
3649     case OBJ_SEQALIGN :
3650       salp = (SeqAlignPtr) ompcp->input_data;
3651       break;
3652     case OBJ_SEQANNOT:
3653       sanp_old = (SeqAnnotPtr) ompcp->input_data;
3654       if (sanp_old->type == 2)
3655       {
3656         salp = sanp_old->data;
3657       }
3658       break;
3659     default :
3660       return OM_MSG_RET_ERROR;
3661   }
3662   if (salp==NULL)
3663      return OM_MSG_RET_ERROR;
3664   entityID = ompcp->input_entityID;
3665   if (entityID < 1)
3666      return OM_MSG_RET_ERROR;
3667 
3668   FixOneAlignmentOverGaps (salp, entityID);
3669   DeleteMarkedObjects (entityID, 0, NULL);
3670 
3671   ObjMgrSetDirtyFlag (entityID, TRUE);
3672 
3673   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
3674 
3675   return OM_MSG_RET_OK;
3676 }
3677 
3678 
3679 typedef struct sqn_bsp {
3680    BioseqPtr  bsp;
3681    struct sqn_bsp PNTR next;
3682 } SQNBsp, PNTR SQNBspPtr;
3683 
SQNGetBioseqsProt(SeqEntryPtr sep,Pointer userdata,Int4 index,Int2 indent)3684 static void SQNGetBioseqsProt(SeqEntryPtr sep, Pointer userdata, Int4 index, Int2 indent)
3685 {
3686    BioseqPtr  bsp = NULL;
3687    SQNBspPtr  sbp;
3688 
3689    if (sep == NULL || sep->data.ptrvalue == NULL || userdata == NULL)
3690       return;
3691    sbp = (SQNBspPtr)userdata;
3692    if (IS_Bioseq(sep))
3693       bsp = (BioseqPtr)(sep->data.ptrvalue);
3694    if (IS_Bioseq(sep) && ISA_aa(bsp->mol))
3695    {
3696       if (sbp->bsp == NULL)
3697          sbp->bsp = (BioseqPtr)(sep->data.ptrvalue);
3698       else
3699       {
3700          while (sbp->next != NULL)
3701          {
3702             sbp = sbp->next;
3703          }
3704          sbp->next = (SQNBspPtr)MemNew(sizeof(SQNBsp));
3705          sbp->next->bsp = (BioseqPtr)(sep->data.ptrvalue);
3706       }
3707    }
3708 }
3709 
3710 typedef struct masterseqform
3711 {
3712   Boolean listBoxAccept;
3713   Boolean listBoxUp;
3714   DialoG  seq_dlg;
3715   GrouP   flipFeatGrp;
3716 } MasterSeqFormData, PNTR MasterSeqFormPtr;
3717 
AcceptMasterSeqMessage(ButtoN b)3718 static void AcceptMasterSeqMessage (ButtoN b)
3719 
3720 {
3721   MasterSeqFormPtr mp;
3722 
3723   mp = (MasterSeqFormPtr) GetObjectExtra (b);
3724   if (mp == NULL) return;
3725   mp->listBoxAccept = TRUE;
3726   mp->listBoxUp = FALSE;
3727 }
3728 
CancelMasterSeqMessage(ButtoN b)3729 static void CancelMasterSeqMessage (ButtoN b)
3730 
3731 {
3732   MasterSeqFormPtr mp;
3733 
3734   mp = (MasterSeqFormPtr) GetObjectExtra (b);
3735   if (mp == NULL) return;
3736   mp->listBoxAccept = FALSE;
3737   mp->listBoxUp = FALSE;
3738 }
3739 
EnableMasterSeqChoice(GrouP g)3740 static void EnableMasterSeqChoice (GrouP g)
3741 {
3742   MasterSeqFormPtr mp;
3743 
3744   mp = (MasterSeqFormPtr) GetObjectExtra (g);
3745   if (mp == NULL) return;
3746   if (GetValue (g) == 1)
3747   {
3748   	Enable (mp->seq_dlg);
3749   	Enable (mp->flipFeatGrp);
3750   }
3751   else
3752   {
3753   	Disable (mp->seq_dlg);
3754   	Disable (mp->flipFeatGrp);
3755   }
3756 }
3757 
SeqNameFromValNodeProc(ValNodePtr vnp)3758 static CharPtr SeqNameFromValNodeProc (ValNodePtr vnp)
3759 {
3760   CharPtr  str;
3761   Int4     buf_size = 41;
3762   SeqIdPtr sip;
3763 
3764   if (vnp == NULL || vnp->data.ptrvalue == NULL)
3765   {
3766     return NULL;
3767   }
3768 
3769   str = (CharPtr) MemNew (buf_size * sizeof (Char));
3770   if (str != NULL)
3771   {
3772     sip = (SeqIdPtr) vnp->data.ptrvalue;
3773     SeqIdWrite (sip, str, PRINTID_REPORT, buf_size - 1);
3774   }
3775   return str;
3776 }
3777 
FreeSeqIdValNode(ValNodePtr vnp)3778 static void FreeSeqIdValNode (ValNodePtr vnp)
3779 {
3780   SeqIdPtr sip;
3781   if (vnp != NULL)
3782   {
3783     sip = (SeqIdPtr) vnp->data.ptrvalue;
3784     SeqIdFree (sip);
3785     vnp->data.ptrvalue = NULL;
3786   }
3787 }
3788 
3789 
CopySeqIDValNode(ValNodePtr vnp)3790 static ValNodePtr CopySeqIDValNode (ValNodePtr vnp)
3791 {
3792   ValNodePtr vnp_new;
3793 
3794   vnp_new = ValNodeNew (NULL);
3795   if (vnp_new != NULL)
3796   {
3797     vnp_new->choice = vnp->choice;
3798     vnp_new->data.ptrvalue = SeqIdDup ((SeqIdPtr)vnp->data.ptrvalue);
3799   }
3800   return vnp_new;
3801 }
3802 
MatchSeqIDValNode(ValNodePtr vnp1,ValNodePtr vnp2)3803 static Boolean MatchSeqIDValNode (ValNodePtr vnp1, ValNodePtr vnp2)
3804 {
3805   if (vnp1 == NULL && vnp2 == NULL)
3806   {
3807     return TRUE;
3808   }
3809   else if (vnp1 == NULL || vnp2 == NULL)
3810   {
3811     return FALSE;
3812   }
3813   else if (SeqIdComp ((SeqIdPtr) vnp1->data.ptrvalue,
3814                       (SeqIdPtr) vnp1->data.ptrvalue) == SIC_YES)
3815   {
3816     return TRUE;
3817   }
3818   else
3819   {
3820     return FALSE;
3821   }
3822 
3823 }
3824 
3825 
GetMasterStrandSeq(ValNodePtr good_list,BioseqPtr PNTR master_bsp,BoolPtr flip_for_aln,BoolPtr flip_feat)3826 static Boolean GetMasterStrandSeq
3827 (ValNodePtr good_list, BioseqPtr PNTR master_bsp, BoolPtr flip_for_aln, BoolPtr flip_feat)
3828 
3829 {
3830   GrouP             c;
3831   GrouP             g;
3832   PrompT            ppt1, ppt2, ppt3, ppt4;
3833   WindoW            w;
3834   MasterSeqFormData md;
3835   ButtoN            b;
3836   GrouP             flipGrp;
3837   ValNodePtr        vnp;
3838 
3839   if (good_list == NULL || master_bsp == NULL || flip_for_aln == NULL || flip_feat == NULL)
3840   {
3841   	return FALSE;
3842   }
3843   md.listBoxUp = TRUE;
3844   md.listBoxAccept = FALSE;
3845   w = ModalWindow (-50, -20, -20, -20, NULL);
3846   if (w != NULL) {
3847     g = HiddenGroup (w, -1, 0, NULL);
3848     SetGroupSpacing (g, 10, 10);
3849     ppt1 = StaticPrompt (g, "The alignment you are attempting to create contains mixed strands.",
3850                          0, 0, programFont, 'c');
3851     ppt2 = StaticPrompt (g, "Do you wish to reverse complement the sequences to form the alignment?",
3852                          0, 0, programFont, 'c');
3853     flipGrp = HiddenGroup (g, 2, 0, EnableMasterSeqChoice);
3854     SetObjectExtra (flipGrp, &md, NULL);
3855     RadioButton (flipGrp, "Yes");
3856     RadioButton (flipGrp, "No");
3857     SetValue (flipGrp, 2);
3858 
3859     ppt3 = StaticPrompt (g, "Reverse the strands for the features as well?", 0, 0, programFont, 'c');
3860     md.flipFeatGrp = HiddenGroup (g, 2, 0, NULL);
3861     RadioButton (md.flipFeatGrp, "Yes");
3862     RadioButton (md.flipFeatGrp, "No");
3863     SetValue (md.flipFeatGrp, 1);
3864     Disable (md.flipFeatGrp);
3865 
3866     ppt4 = StaticPrompt (g, "Choose a sequence with the correct strand", 0, 0, programFont, 'c');
3867     md.seq_dlg = ValNodeSelectionDialog (g, good_list, 8,
3868                                             SeqNameFromValNodeProc,
3869                                             FreeSeqIdValNode,
3870                                             CopySeqIDValNode,
3871                                             MatchSeqIDValNode,
3872                                             "sequence",
3873                                             NULL, NULL, FALSE);
3874     Disable (md.seq_dlg);
3875     c = HiddenGroup (g, 2, 0, NULL);
3876     b = DefaultButton (c, "Accept", AcceptMasterSeqMessage);
3877     SetObjectExtra (b, &md, NULL);
3878     b = PushButton (c, "Cancel", CancelMasterSeqMessage);
3879     SetObjectExtra (b, &md, NULL);
3880     AlignObjects (ALIGN_CENTER, (HANDLE) ppt1, (HANDLE) ppt2, (HANDLE) flipGrp,
3881                   (HANDLE) ppt3, (HANDLE) md.flipFeatGrp,
3882                   (HANDLE) ppt4, (HANDLE) md.seq_dlg,
3883                   (HANDLE) c, NULL);
3884     RealizeWindow (w);
3885     Show (w);
3886     Select (w);
3887     while (md.listBoxUp) {
3888       ProcessExternalEvent ();
3889       Update ();
3890     }
3891     ProcessAnEvent ();
3892 
3893     if (GetValue (flipGrp) == 1)
3894     {
3895       *flip_for_aln = TRUE;
3896       vnp = DialogToPointer (md.seq_dlg);
3897       if (vnp == NULL)
3898       {
3899         md.listBoxAccept = FALSE;
3900       }
3901       else
3902       {
3903         *master_bsp = BioseqFind ((SeqIdPtr)vnp->data.ptrvalue);
3904       }
3905       if (GetValue (md.flipFeatGrp) == 1)
3906       {
3907       	*flip_feat = TRUE;
3908       }
3909       else
3910       {
3911       	*flip_feat = FALSE;
3912       }
3913     }
3914     else
3915     {
3916       *flip_for_aln = FALSE;
3917     }
3918     Remove (w);
3919   }
3920   return md.listBoxAccept;
3921 }
3922 
FreeSequenceIDValNodeList(ValNodePtr seqlist)3923 static ValNodePtr FreeSequenceIDValNodeList (ValNodePtr seqlist)
3924 {
3925   ValNodePtr vnp;
3926   SeqIdPtr   sip;
3927 
3928   if (seqlist == NULL) return NULL;
3929   for (vnp = seqlist; vnp != NULL; vnp = vnp->next)
3930   {
3931     sip = (SeqIdPtr) vnp->data.ptrvalue;
3932     SeqIdFree (sip);
3933   }
3934   ValNodeFree (seqlist);
3935   return NULL;
3936 }
3937 
GetBadSequencesAndReversals(SQNBspPtr sbp,Uint2 entityID,Boolean use_new_blast,BoolPtr some_reversed,Int4Ptr num_seqs,ValNodePtr PNTR good_list_ptr,ValNodePtr PNTR bad_list_ptr)3938 static void GetBadSequencesAndReversals
3939 (SQNBspPtr       sbp,
3940  Uint2           entityID,
3941  Boolean         use_new_blast,
3942  BoolPtr         some_reversed,
3943  Int4Ptr         num_seqs,
3944  ValNodePtr PNTR good_list_ptr,
3945  ValNodePtr PNTR bad_list_ptr)
3946 {
3947   Boolean           revcomp = FALSE;
3948   SQNBspPtr         sbp_idx;
3949   SeqAlignPtr       salp;
3950   ValNodePtr        bad_list = NULL, vnp;
3951   SeqIdPtr          tmp_id;
3952   Boolean           dirty;
3953   ValNodePtr        good_list = NULL;
3954 
3955   if (sbp == NULL) return;
3956   if (some_reversed != NULL)
3957   {
3958     *some_reversed = FALSE;
3959   }
3960 
3961   if (num_seqs != NULL)
3962   {
3963     *num_seqs = 1;
3964   }
3965   for (sbp_idx = sbp->next; sbp_idx != NULL; sbp_idx = sbp_idx->next)
3966   {
3967     if (num_seqs != NULL)
3968     {
3969       (*num_seqs) ++;
3970     }
3971     revcomp = FALSE;
3972     if (use_new_blast)
3973     {
3974       salp = Sequin_GlobalAlign2Seq(sbp->bsp, sbp_idx->bsp, &revcomp);
3975     }
3976     else
3977     {
3978       salp = Sqn_GlobalAlign2Seq(sbp->bsp, sbp_idx->bsp, &revcomp);
3979     }
3980     if (salp == NULL || ! ValidateSeqAlign (salp, entityID, FALSE, FALSE, TRUE, FALSE, FALSE, &dirty))
3981     {
3982       tmp_id = SeqIdDup (SeqIdFindBest (sbp_idx->bsp->id, 0));
3983       if (tmp_id != NULL)
3984       {
3985         vnp = ValNodeNew (bad_list);
3986         if (vnp != NULL)
3987         {
3988           vnp->data.ptrvalue = tmp_id;
3989         }
3990         if (bad_list == NULL)
3991         {
3992           bad_list = vnp;
3993         }
3994       }
3995     }
3996     else
3997     {
3998       if (good_list == NULL)
3999       {
4000         /* add master sequence to good list */
4001         tmp_id = SeqIdDup (SeqIdFindBest (sbp->bsp->id, 0));
4002         ValNodeAddPointer (&good_list, 0, tmp_id);
4003       }
4004       tmp_id = SeqIdDup (SeqIdFindBest (sbp_idx->bsp->id, 0));
4005       if (tmp_id != NULL)
4006       {
4007         vnp = ValNodeNew (good_list);
4008         if (vnp != NULL)
4009         {
4010           vnp->data.ptrvalue = tmp_id;
4011         }
4012         if (good_list == NULL)
4013         {
4014           good_list = vnp;
4015         }
4016       }
4017       if (revcomp)
4018       {
4019         if (some_reversed != NULL)
4020         {
4021           *some_reversed = TRUE;
4022         }
4023       }
4024     }
4025     SeqAlignFree (salp);
4026     if (revcomp)
4027     {
4028       BioseqRevComp (sbp_idx->bsp);
4029       ReverseBioseqFeatureStrands (sbp_idx->bsp);
4030     }
4031   }
4032   if (good_list_ptr != NULL)
4033   {
4034     *good_list_ptr = good_list;
4035   }
4036   else
4037   {
4038     FreeSequenceIDValNodeList (good_list);
4039   }
4040   if (bad_list_ptr != NULL)
4041   {
4042     *bad_list_ptr = bad_list;
4043   }
4044   else
4045   {
4046     FreeSequenceIDValNodeList (bad_list);
4047   }
4048 }
4049 
ContinueWithBadSequences(ValNodePtr bad_list,Int4 num_seqs)4050 static MsgAnswer ContinueWithBadSequences (ValNodePtr bad_list, Int4 num_seqs)
4051 {
4052   Int4       num_bad_seq;
4053   Char       buf [41];
4054   CharPtr    msg_start = "BLAST is unable to create valid pairwise "
4055            "alignments for the following sequences:\n";
4056   CharPtr    msg_end = "Do you want to create this alignment without "
4057            "these sequences?";
4058   CharPtr    msg;
4059   Int4       msg_len;
4060   ValNodePtr vnp;
4061   SeqIdPtr   tmp_id;
4062   MsgAnswer  ans = ANS_YES;
4063 
4064   if (bad_list == NULL) return ANS_YES;
4065   num_bad_seq = ValNodeLen (bad_list);
4066   if (num_bad_seq == 0) return ANS_YES;
4067   if (num_bad_seq == num_seqs)
4068   {
4069     Message (MSG_ERROR, "BLAST is unable to create valid pairwise alignments "
4070              "for any of the sequences.  No alignment will be created.");
4071     return ANS_NO;
4072   }
4073   msg_len = StringLen (msg_start) + StringLen (msg_end)
4074             + num_bad_seq * (sizeof (buf) + 2) + 3;
4075 
4076   msg = (CharPtr) MemNew (msg_len * sizeof (Char));
4077   if (msg != NULL)
4078   {
4079     StringCat (msg, msg_start);
4080     for (vnp = bad_list; vnp != NULL; vnp = vnp->next)
4081     {
4082       tmp_id = (SeqIdPtr) vnp->data.ptrvalue;
4083       SeqIdWrite (tmp_id, buf, PRINTID_REPORT, sizeof (buf) - 1);
4084       StringCat (msg, buf);
4085       if (vnp->next != NULL)
4086       {
4087         StringCat (msg, ", ");
4088       }
4089     }
4090     StringCat (msg, msg_end);
4091     ans = Message (MSG_YN, msg);
4092     MemFree (msg);
4093   }
4094   return ans;
4095 }
4096 
4097 /* In order to create alignments for segmented sets, first need to change
4098  * method of collecting bioseqs to collect one set per segment, then
4099  * need to to process each set individually.
4100  */
FindSegSetsCallback(BioseqSetPtr bssp,Pointer userdata)4101 static void FindSegSetsCallback (BioseqSetPtr bssp, Pointer userdata)
4102 {
4103   SeqEntryPtr     sep;
4104   BioseqSetPtr    segment_set = NULL;
4105   ValNodePtr      vnp;
4106   ValNodePtr PNTR seg_list;
4107   SQNBspPtr       sbp;
4108 
4109   if (bssp == NULL || bssp->_class != BioseqseqSet_class_segset
4110       || userdata == NULL) return;
4111 
4112   for (sep = bssp->seq_set; sep != NULL && segment_set == NULL; sep = sep->next)
4113   {
4114     if (IS_Bioseq_set (sep))
4115     {
4116       segment_set = sep->data.ptrvalue;
4117       if (segment_set != NULL && segment_set->_class != BioseqseqSet_class_parts)
4118       {
4119         segment_set = NULL;
4120       }
4121     }
4122   }
4123   if (segment_set != NULL)
4124   {
4125     seg_list = (ValNodePtr PNTR) userdata;
4126     vnp = *seg_list;
4127     for (sep = segment_set->seq_set; sep != NULL; sep = sep->next)
4128     {
4129       if (!IS_Bioseq (sep)) continue;
4130       if (vnp == NULL)
4131       {
4132         vnp = ValNodeNew (*seg_list);
4133         if (*seg_list == NULL)
4134         {
4135           *seg_list = vnp;
4136         }
4137         sbp = MemNew (sizeof (SQNBsp));
4138         sbp->bsp = (BioseqPtr)sep->data.ptrvalue;
4139         sbp->next = NULL;
4140         vnp->data.ptrvalue = sbp;
4141       }
4142       else
4143       {
4144         sbp = (SQNBspPtr) vnp->data.ptrvalue;
4145         if (sbp == NULL)
4146         {
4147           sbp = MemNew (sizeof (SQNBsp));
4148           sbp->bsp = (BioseqPtr)sep->data.ptrvalue;
4149           sbp->next = NULL;
4150           vnp->data.ptrvalue = sbp;
4151         }
4152         else
4153         {
4154           while (sbp->next != NULL)
4155           {
4156             sbp = sbp->next;
4157           }
4158           sbp->next = (SQNBspPtr)MemNew(sizeof(SQNBsp));
4159           sbp->next->bsp = (BioseqPtr)(sep->data.ptrvalue);
4160         }
4161       }
4162       vnp = vnp->next;
4163     }
4164   }
4165 }
4166 
FindNucBioseqsCallback(BioseqPtr bsp,Pointer userdata)4167 static void FindNucBioseqsCallback (BioseqPtr bsp, Pointer userdata)
4168 {
4169   ValNodePtr PNTR seg_list;
4170   ValNodePtr      vnp;
4171   SQNBspPtr       sbp;
4172 
4173   if (bsp == NULL || ! ISA_na(bsp->mol) || userdata == NULL)
4174     return;
4175 
4176   seg_list = (ValNodePtr PNTR) userdata;
4177   if (*seg_list == NULL)
4178   {
4179     vnp = ValNodeNew (*seg_list);
4180     if (vnp == NULL) return;
4181     *seg_list = vnp;
4182   }
4183   else
4184   {
4185     vnp = *seg_list;
4186   }
4187   sbp = (SQNBspPtr)vnp->data.ptrvalue;
4188   if (sbp == NULL)
4189   {
4190     sbp = MemNew (sizeof (SQNBsp));
4191     if (sbp == NULL) return;
4192     sbp->bsp = bsp;
4193     sbp->next = NULL;
4194     vnp->data.ptrvalue = sbp;
4195   }
4196   else
4197   {
4198     while (sbp->next != NULL)
4199     {
4200       sbp = sbp->next;
4201     }
4202     sbp->next = (SQNBspPtr)MemNew(sizeof(SQNBsp));
4203     sbp->next->bsp = bsp;
4204   }
4205 }
4206 
GetAlignmentSegmentsList(SeqEntryPtr sep)4207 static ValNodePtr GetAlignmentSegmentsList (SeqEntryPtr sep)
4208 {
4209   ValNodePtr seg_list = NULL;
4210   if (sep == NULL) return NULL;
4211 
4212   VisitSetsInSep (sep, &seg_list, FindSegSetsCallback);
4213   if (seg_list == NULL)
4214   {
4215     VisitBioseqsInSep (sep, &seg_list, FindNucBioseqsCallback);
4216   }
4217   return seg_list;
4218 }
4219 
4220 /* This function finds the zero-based index of the single sequence in an alignment
4221  * that extends past the left side of an alignment (like a sore thumb).
4222  */
FindAlignmentLeftThumb(SeqAlignPtr salp)4223 static Int4 FindAlignmentLeftThumb (SeqAlignPtr salp)
4224 {
4225   DenseSegPtr dsp;
4226   Int4        k;
4227   Int4        sore_thumb = -1; /* because the sequence in question sticks out... */
4228   BioseqPtr   bsp;
4229   SeqIdPtr    sip;
4230 
4231   if (salp == NULL || salp->segtype != SAS_DENSEG || salp->segs == NULL)
4232   {
4233     return -1;
4234   }
4235 
4236   /* we need to examine the alignment, to see if there is a single sequence
4237    * that extends before the beginning of the alignment or past the end of
4238    * the alignment, so that we can insert additional segments with gaps for
4239    * all other sequences.
4240    */
4241 
4242   dsp = (DenseSegPtr) salp->segs;
4243 
4244   /* check left end of alignment */
4245   for (k = 0, sip = dsp->ids; k < dsp->dim; k++, sip = sip->next)
4246   {
4247     if (dsp->strands [k] == Seq_strand_minus)
4248     {
4249       bsp = BioseqFind (sip);
4250       if (bsp != NULL
4251           && dsp->starts [k] + dsp->lens [0] < bsp->length
4252           && dsp->starts [k] > -1)
4253       {
4254         if (sore_thumb != -1)
4255         {
4256           /* can only do this when only one sequence extends past the end */
4257           return -1;
4258         }
4259         else
4260         {
4261           sore_thumb = k;
4262         }
4263       }
4264     }
4265     else if (dsp->starts [k] > 0)
4266     {
4267       if (sore_thumb != -1)
4268       {
4269         /* can only do this when only one sequence extends past the end */
4270         return -1;
4271       }
4272       else
4273       {
4274         sore_thumb = k;
4275       }
4276     }
4277   }
4278 
4279   return sore_thumb;
4280 }
4281 
4282 /* This function finds the zero-based index of the single sequence in an alignment
4283  * that extends past the right side of an alignment (like a sore thumb).
4284  */
FindAlignmentRightThumb(SeqAlignPtr salp)4285 static Int4 FindAlignmentRightThumb (SeqAlignPtr salp)
4286 {
4287   DenseSegPtr dsp;
4288   Int4        k, start_index;
4289   Int4        sore_thumb = -1; /* because the sequence in question sticks out... */
4290   BioseqPtr   bsp;
4291   SeqIdPtr    sip;
4292 
4293   if (salp == NULL || salp->segtype != SAS_DENSEG || salp->segs == NULL)
4294   {
4295     return -1;
4296   }
4297 
4298   /* we need to examine the alignment, to see if there is a single sequence
4299    * that extends before the beginning of the alignment or past the end of
4300    * the alignment, so that we can insert additional segments with gaps for
4301    * all other sequences.
4302    */
4303 
4304   dsp = (DenseSegPtr) salp->segs;
4305 
4306   /* check right end of alignment */
4307   for (k = 0, sip = dsp->ids; k < dsp->dim; k++, sip = sip->next)
4308   {
4309     start_index = (dsp->dim * (dsp->numseg - 1)) + k ;
4310     if (dsp->strands [start_index] == Seq_strand_minus)
4311     {
4312       if (dsp->starts [start_index] > 0)
4313       {
4314         if (sore_thumb != -1)
4315         {
4316           /* can only do this when only one sequence extends past the end */
4317           return -1;
4318         }
4319         else
4320         {
4321           sore_thumb = k;
4322         }
4323       }
4324     }
4325     else
4326     {
4327       bsp = BioseqFind (sip);
4328       if (bsp != NULL
4329           && dsp->starts [start_index] > -1
4330           && dsp->starts [start_index] + dsp->lens [dsp->numseg - 1] < bsp->length)
4331       {
4332         if (sore_thumb != -1)
4333         {
4334           /* can only do this when only one sequence extends past the end */
4335           return -1;
4336         }
4337         else
4338         {
4339           sore_thumb = k;
4340         }
4341       }
4342     }
4343   }
4344 
4345   return sore_thumb;
4346 }
4347 
4348 /* This function looks for a single sequence extending past the left side of the
4349  * alignment and/or a single sequence extending past the right side of the alignment
4350  * and extends the alignment to cover these sequences, with gaps in the alignment for
4351  * all of the other sequences.
4352  * The function is unable to extend the alignment if more than one sequence extends
4353  * past the end of the alignment on that side.
4354  */
FixAlignmentEndStubs(SeqAlignPtr salp)4355 static void FixAlignmentEndStubs (SeqAlignPtr salp)
4356 {
4357   DenseSegPtr dsp, dsp_new;
4358   Int4        k;
4359   Int4        left_thumb, right_thumb; /* because the sequence in question sticks out... */
4360   BioseqPtr   bsp;
4361   Int4        extra_segs = 0, seg_offset = 0;
4362   SeqIdPtr    sip;
4363   Int4        new_index, old_index;
4364   Int4        thumb_len;
4365 
4366   if (salp == NULL || salp->segtype != SAS_DENSEG || salp->segs == NULL)
4367   {
4368     return;
4369   }
4370 
4371   /* we need to examine the alignment, to see if there is a single sequence
4372    * that extends before the beginning of the alignment or past the end of
4373    * the alignment, so that we can insert additional segments with gaps for
4374    * all other sequences.
4375    */
4376 
4377   dsp = (DenseSegPtr) salp->segs;
4378 
4379   left_thumb = FindAlignmentLeftThumb (salp);
4380   right_thumb = FindAlignmentRightThumb (salp);
4381 
4382   if (left_thumb == -1 && right_thumb == 1)
4383   {
4384     return;
4385   }
4386 
4387   if (left_thumb != -1)
4388   {
4389     extra_segs ++;
4390   }
4391   if (right_thumb != -1)
4392   {
4393     extra_segs ++;
4394   }
4395 
4396   /* insert sequence for the thumb and gap for all of the other sequences at the
4397    * beginning of the alignment or end of the alignment.
4398    */
4399 
4400   dsp_new = DenseSegNew();
4401   dsp_new->dim = dsp->dim;
4402   dsp_new->numseg = dsp->numseg + extra_segs;
4403   dsp_new->starts = (Int4Ptr) MemNew(dsp_new->dim * dsp_new->numseg * sizeof(Int4));
4404   dsp_new->lens = (Int4Ptr) MemNew(dsp_new->numseg * sizeof(Int4));
4405   dsp_new->strands = (Uint1Ptr) MemNew (dsp_new->dim * dsp_new->numseg * sizeof(Int4));
4406   dsp_new->ids = dsp->ids;
4407   dsp->ids = NULL;
4408 
4409   if (left_thumb != -1)
4410   {
4411     for (k = 0, sip = dsp_new->ids; k < dsp_new->dim; k++, sip = sip->next)
4412     {
4413       if (k == left_thumb)
4414       {
4415         if (dsp->strands [k] == Seq_strand_minus)
4416         {
4417           bsp = BioseqFind (sip);
4418           if (bsp == NULL)
4419           {
4420             dsp->ids = dsp_new->ids;
4421             dsp_new->ids = NULL;
4422             DenseSegFree (dsp_new);
4423             return;
4424           }
4425           thumb_len = bsp->length - dsp->starts [k] - dsp->lens [0];
4426           dsp_new->starts [k] = bsp->length - thumb_len;
4427           dsp_new->lens [0] = thumb_len;
4428           dsp_new->strands [k] = Seq_strand_minus;
4429         }
4430         else
4431         {
4432           dsp_new->starts [k] = 0;
4433           dsp_new->lens [0] = dsp->starts [k];
4434           dsp_new->strands [k] = Seq_strand_plus;
4435         }
4436       }
4437       else
4438       {
4439         dsp_new->starts [k] = -1;
4440         /* keep strand consistent with first segment */
4441         dsp_new->strands [k] = dsp->strands [k];
4442       }
4443     }
4444     seg_offset ++;
4445   }
4446 
4447   /* copy middle alignment starts and strands */
4448   for (k = 0; k < dsp->dim * dsp->numseg; k++)
4449   {
4450     dsp_new->starts [k + (dsp->dim * seg_offset)] = dsp->starts [k];
4451     dsp_new->strands [k + (dsp->dim * seg_offset)] = dsp->strands [k];
4452   }
4453   /* copy middle alignment lens */
4454   for (k = 0; k < dsp->numseg; k++)
4455   {
4456     dsp_new->lens [k + seg_offset] = dsp->lens [k];
4457   }
4458 
4459   /* add final segment */
4460   if (right_thumb != -1)
4461   {
4462     for (k = 0, sip = dsp_new->ids; k < dsp->dim; k++, sip = sip->next)
4463     {
4464       new_index = dsp_new->dim * (dsp_new->numseg - 1) + k;
4465       old_index = dsp->dim * (dsp->numseg - 1) + k;
4466 
4467       if (k == right_thumb)
4468       {
4469         if (dsp->strands [old_index] == Seq_strand_minus)
4470         {
4471           dsp_new->starts [new_index] = 0;
4472           dsp_new->strands [new_index] = Seq_strand_minus;
4473           dsp_new->lens [dsp_new->numseg - 1] = dsp->starts [old_index];
4474         }
4475         else
4476         {
4477           bsp = BioseqFind (sip);
4478           thumb_len = bsp->length - dsp->starts [old_index] - dsp->lens [dsp->numseg - 1];
4479           dsp_new->starts [new_index] = bsp->length - thumb_len;
4480           dsp_new->lens [dsp_new->numseg - 1] = thumb_len;
4481           dsp_new->strands [new_index] = Seq_strand_plus;
4482         }
4483       }
4484       else
4485       {
4486         dsp_new->starts [new_index] = -1;
4487         /* keep strands consistent */
4488         dsp_new->strands [new_index] = dsp->strands [old_index];
4489       }
4490     }
4491   }
4492 
4493   /* free the old alignment */
4494   dsp = DenseSegFree(dsp);
4495 
4496   /* replace it with the new alignment */
4497   salp->segs = (Pointer)(dsp_new);
4498 
4499   /* reindex the alignment */
4500   SAIndex2Free2(salp->saip);
4501   salp->saip = NULL;
4502   AlnMgr2IndexSingleChildSeqAlign(salp);
4503 }
4504 
CreateOneAlignment(SQNBspPtr sbp,Uint2 entityID,BioseqSetPtr bssp,Boolean use_new_blast,FILE * fp,BoolPtr errors_in_log)4505 static Int2 CreateOneAlignment
4506 (SQNBspPtr    sbp,
4507  Uint2        entityID,
4508  BioseqSetPtr bssp,
4509  Boolean      use_new_blast,
4510  FILE         *fp,
4511  BoolPtr      errors_in_log)
4512 {
4513   BioseqPtr         master_bsp;
4514   Boolean           some_reversed;
4515   ValNodePtr        bad_list, good_list;
4516   MsgAnswer         continue_with_bad;
4517   Int4              num_seqs = 0;
4518   Boolean           flip_for_aln = FALSE;
4519   Boolean           flip_feat = FALSE;
4520   SeqAlignPtr       salp, salp_head, salp_prev, salp_tmp, salp_mult;
4521   Boolean           revcomp = FALSE;
4522   SeqIdPtr          sip, sip1, sip2;
4523   Char              buf [41];
4524   BioseqPtr         bsp;
4525   SQNBspPtr         sbp_prev;
4526   Boolean           dirty;
4527   DenseSegPtr       dsp;
4528   ValNodePtr        vnp;
4529   Int4              num_reversed = 0;
4530 
4531   if (sbp == NULL || errors_in_log == NULL) return OM_MSG_RET_ERROR;
4532 
4533   master_bsp = sbp->bsp;
4534   GetBadSequencesAndReversals (sbp, entityID, use_new_blast, &some_reversed, &num_seqs, &good_list, &bad_list);
4535   continue_with_bad = ContinueWithBadSequences(bad_list, num_seqs);
4536   if (continue_with_bad != ANS_YES)
4537   {
4538     bad_list = FreeSequenceIDValNodeList (bad_list);
4539     return OM_MSG_RET_DONE;
4540   }
4541   if (some_reversed)
4542   {
4543     if (! GetMasterStrandSeq (good_list, &master_bsp, &flip_for_aln, &flip_feat))
4544     {
4545       bad_list = FreeSequenceIDValNodeList (bad_list);
4546       return OM_MSG_RET_ERROR;
4547     }
4548   }
4549 
4550   if (bad_list != NULL)
4551   {
4552     fprintf (fp, "The following sequences were omitted from the alignment:\n");
4553     for (vnp = bad_list; vnp != NULL; vnp = vnp->next)
4554     {
4555       sip = (SeqIdPtr) vnp->data.ptrvalue;
4556       SeqIdWrite (sip, buf, PRINTID_REPORT, sizeof (buf) - 1);
4557       fprintf (fp, "%s\n", buf);
4558     }
4559     bad_list = FreeSequenceIDValNodeList (bad_list);
4560     *errors_in_log = TRUE;
4561   }
4562 
4563   if (flip_for_aln && master_bsp != sbp->bsp)
4564   {
4565     /* we align the master with the top of the list - this will reverse the strandedness
4566      * of the top of the list if necessary.
4567      */
4568     revcomp = FALSE;
4569     if (use_new_blast)
4570     {
4571       salp = Sequin_GlobalAlign2Seq(master_bsp, sbp->bsp, &revcomp);
4572     }
4573     else
4574     {
4575       salp = Sqn_GlobalAlign2Seq(master_bsp, sbp->bsp, &revcomp);
4576     }
4577     SeqAlignFree (salp);
4578     if (revcomp)
4579     {
4580       if (!flip_feat)
4581       {
4582         ReverseBioseqFeatureStrands (sbp->bsp);
4583       }
4584       fprintf (fp, "The following sequences were reversed in order to "
4585          	              "construct the alignment:\n");
4586       sip = SeqIdFindBest(sbp->bsp->id, 0);
4587       SeqIdWrite (sip, buf, PRINTID_REPORT, sizeof (buf) - 1);
4588       fprintf (fp, "%s\n", buf);
4589       num_reversed ++;
4590     }
4591   }
4592 
4593   bsp = sbp->bsp;
4594   sbp_prev = sbp;
4595   sbp = sbp->next;
4596   MemFree(sbp_prev);
4597   salp_head = salp_prev = NULL;
4598 
4599 
4600   num_seqs = 1;
4601   while (sbp != NULL)
4602   {
4603     if (ISA_na(sbp->bsp->mol))
4604     {
4605        sip1 = SeqIdDup(bsp->id);
4606        sip2 = SeqIdDup(sbp->bsp->id);
4607        revcomp = FALSE;
4608        if (use_new_blast)
4609        {
4610          salp = Sequin_GlobalAlign2Seq(bsp, sbp->bsp, &revcomp);
4611        }
4612        else
4613        {
4614          salp = Sqn_GlobalAlign2Seq(bsp, sbp->bsp, &revcomp);
4615        }
4616 
4617        /* count the number of sequences we are trying to align */
4618        num_seqs ++;
4619 
4620        if (salp != NULL
4621            && ! ValidateSeqAlign (salp, entityID, FALSE, FALSE, TRUE, FALSE, FALSE, &dirty))
4622        {
4623          /* if an alignment was created and the sequence was reversed to create the alignment,
4624           * but the new alignment wasn't valid, un-reverse the sequence and don't add the
4625           * sequence to the list of sequences reversed.
4626           */
4627          salp = SeqAlignFree (salp);
4628          if (revcomp)
4629          {
4630            BioseqRevComp (sbp->bsp);
4631            ReverseBioseqFeatureStrands (sbp->bsp);
4632            revcomp = FALSE;
4633          }
4634        }
4635 
4636        if (salp != NULL)
4637        {
4638          if (revcomp) {
4639            if (flip_for_aln)
4640            {
4641              if (!flip_feat)
4642              {
4643                ReverseBioseqFeatureStrands (sbp->bsp);
4644              }
4645              if (num_reversed == 0)
4646              {
4647              	 fprintf (fp, "The following sequences were reversed in order to "
4648          	              "construct the alignment:\n");
4649              }
4650              sip = SeqIdFindBest(sbp->bsp->id, 0);
4651              SeqIdWrite (sip, buf, PRINTID_REPORT, sizeof (buf) - 1);
4652              fprintf (fp, "%s\n", buf);
4653              num_reversed ++;
4654            }
4655            else
4656            {
4657              /* un-reverse the sequence */
4658              BioseqRevComp (sbp->bsp);
4659              ReverseBioseqFeatureStrands (sbp->bsp);
4660              /* change the alignment to show the reversed strand */
4661              ReverseAlignmentStrand (salp, 2);
4662            }
4663            revcomp = FALSE;
4664          }
4665 
4666          dsp = (DenseSegPtr)(salp->segs);
4667          SeqIdSetFree(dsp->ids);
4668          dsp->ids = sip1;
4669          dsp->ids->next = sip2;
4670          if (salp != NULL && salp_head != NULL) {
4671             salp_prev->next = salp;
4672             salp_prev = salp;
4673          } else if (salp != NULL) {
4674           salp_head = salp_prev = salp;
4675          }
4676        }
4677     }
4678     sbp_prev = sbp;
4679     sbp = sbp->next;
4680     MemFree(sbp_prev);
4681   }
4682   if (salp_head != NULL)
4683   {
4684     salp_tmp = salp_head;
4685     while (salp_tmp != NULL)
4686     {
4687        if (salp_tmp->saip != NULL)
4688        {
4689           SeqAlignIndexFree(salp_tmp->saip);
4690           salp_tmp->saip = NULL;
4691        }
4692        salp_tmp = salp_tmp->next;
4693     }
4694     AlnMgr2IndexSeqAlignEx(salp_head, FALSE);
4695     salp_mult = AlnMgr2GetSubAlign(salp_head, 0, -1, 0, TRUE);
4696     salp_mult->dim = AlnMgr2GetNumRows(salp_head);
4697     salp_mult->type = SAT_PARTIAL;
4698 
4699     FixAlignmentEndStubs (salp_mult);
4700 
4701     ValidateSeqAlign (salp_mult, entityID, TRUE, FALSE, TRUE, FALSE, FALSE, &dirty);
4702     SeqAlignSetFree(salp_head);
4703 
4704     /* index multiple alignment */
4705     AlnMgr2IndexSeqAlignEx(salp_mult, FALSE);
4706 
4707     /* break up alignment if it covers gaps of unknown length */
4708     salp_mult = MakeDiscontiguousAlignments (salp_mult);
4709 
4710   } else
4711     salp_mult = NULL;
4712 
4713   if (salp_mult != NULL)
4714   {
4715     /* create separate SeqAnnots for each alignment in the chain */
4716     CreateSeqAnnotsForDiscontiguousAlignments (salp_mult, entityID, bssp);
4717     ObjMgrSetDirtyFlag (entityID, TRUE);
4718     ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
4719   }
4720   if (num_reversed > 0)
4721   {
4722     fprintf (fp, "%d out of %d sequences were reversed.\n", num_reversed, num_seqs);
4723     *errors_in_log = TRUE;
4724   }
4725   return OM_MSG_RET_DONE;
4726 }
4727 
ReOrderOneListForMaster(ValNodePtr one_list,Int4 master_pos)4728 static void ReOrderOneListForMaster (ValNodePtr one_list, Int4 master_pos)
4729 {
4730   SQNBspPtr         sbp, sbp_prev;
4731   Int4              seg_pos;
4732 
4733   if (one_list == NULL || one_list->data.ptrvalue == NULL || master_pos < 2)
4734   {
4735     return;
4736   }
4737 
4738   sbp = (SQNBspPtr) one_list->data.ptrvalue;
4739 
4740   sbp_prev = sbp;
4741   sbp = sbp->next;
4742   seg_pos = 2;
4743   while (sbp != NULL && seg_pos != master_pos)
4744   {
4745     sbp_prev = sbp;
4746     sbp = sbp->next;
4747     seg_pos++;
4748   }
4749 
4750   if (sbp != NULL)
4751   {
4752     sbp_prev->next = sbp->next;
4753     sbp->next = (SQNBspPtr) one_list->data.ptrvalue;
4754     one_list->data.ptrvalue = sbp;
4755   }
4756 }
4757 
GetMasterSeq(ValNodePtr seg_aln_list)4758 static Boolean GetMasterSeq (ValNodePtr seg_aln_list)
4759 
4760 {
4761   GrouP             c;
4762   GrouP             g;
4763   PrompT            ppt1;
4764   WindoW            w;
4765   MasterSeqFormData md;
4766   ButtoN            b;
4767   ValNodePtr        choice_name_list = NULL, vnp;
4768   SQNBspPtr         sbp, seg_list;
4769   Char              buf [41];
4770   Int4              master_pos;
4771   SeqIdPtr          sip;
4772 
4773   if (seg_aln_list == NULL || seg_aln_list->data.ptrvalue == NULL)
4774   {
4775   	return FALSE;
4776   }
4777   md.listBoxUp = TRUE;
4778   md.listBoxAccept = FALSE;
4779   w = ModalWindow (-50, -20, -20, -20, NULL);
4780   if (w == NULL)
4781   {
4782     return FALSE;
4783   }
4784 
4785   g = HiddenGroup (w, -1, 0, NULL);
4786   SetGroupSpacing (g, 10, 10);
4787   ppt1 = StaticPrompt (g, "Select the master sequence for this alignment.",
4788                        0, 0, programFont, 'c');
4789 
4790   seg_list = (SQNBspPtr) seg_aln_list->data.ptrvalue;
4791   for (sbp = seg_list; sbp != NULL; sbp = sbp->next)
4792   {
4793     sip = SeqIdFindBest (sbp->bsp->id, 0);
4794     SeqIdWrite (sip, buf, PRINTID_REPORT, sizeof (buf) - 1);
4795     ValNodeAddPointer (&choice_name_list, 0, StringSave (buf));
4796   }
4797   md.seq_dlg = SelectionDialog (g, NULL, NULL, FALSE, "sequence", choice_name_list, 8);
4798   choice_name_list = ValNodeFreeData (choice_name_list);
4799 
4800   c = HiddenGroup (g, 2, 0, NULL);
4801   b = DefaultButton (c, "Accept", AcceptMasterSeqMessage);
4802   SetObjectExtra (b, &md, NULL);
4803   b = PushButton (c, "Cancel", CancelMasterSeqMessage);
4804   SetObjectExtra (b, &md, NULL);
4805   AlignObjects (ALIGN_CENTER, (HANDLE) ppt1, (HANDLE) md.seq_dlg,
4806                 (HANDLE) c, NULL);
4807   RealizeWindow (w);
4808   Show (w);
4809   Select (w);
4810   while (md.listBoxUp) {
4811     ProcessExternalEvent ();
4812     Update ();
4813   }
4814   ProcessAnEvent ();
4815 
4816   vnp = DialogToPointer (md.seq_dlg);
4817   if (vnp == NULL || vnp->data.intvalue == 0)
4818   {
4819     md.listBoxAccept = FALSE;
4820   }
4821   else
4822   {
4823     master_pos = vnp->data.intvalue;
4824     for (vnp = seg_aln_list; vnp != NULL; vnp = vnp->next)
4825     {
4826       ReOrderOneListForMaster (vnp, master_pos);
4827     }
4828   }
4829   Remove (w);
4830   return md.listBoxAccept;
4831 }
4832 
4833 
AddSeqAlignForSeqEntry(SeqEntryPtr sep,Uint2 entityID,Boolean choose_master,Boolean use_new_blast)4834 extern Int2 AddSeqAlignForSeqEntry (SeqEntryPtr sep, Uint2 entityID, Boolean choose_master, Boolean use_new_blast)
4835 {
4836   SQNBspPtr         sbp;
4837   Char              path [PATH_MAX]; /* path for log of sequences reversed during alignment */
4838   FILE             *fp;              /* file pointer for sequence reverse log */
4839   Boolean           errors_in_log = FALSE;
4840   ValNodePtr        seg_aln_list, vnp;
4841   BioseqSetPtr      bssp = NULL;
4842 
4843   if (sep == NULL || sep->data.ptrvalue == NULL || !IS_Bioseq_set (sep)) return OM_MSG_RET_ERROR;
4844 
4845   bssp = (BioseqSetPtr) sep->data.ptrvalue;
4846   seg_aln_list = GetAlignmentSegmentsList (sep);
4847 
4848   if (choose_master)
4849   {
4850     if (!GetMasterSeq (seg_aln_list))
4851     {
4852       return OM_MSG_RET_ERROR;
4853     }
4854   }
4855 
4856   TmpNam (path);
4857   fp = FileOpen (path, "wb");
4858   if (fp == NULL) return OM_MSG_RET_ERROR;
4859 
4860   for (vnp = seg_aln_list; vnp != NULL; vnp = vnp->next)
4861   {
4862     sbp = vnp->data.ptrvalue;
4863     if (sbp == NULL) continue;
4864     CreateOneAlignment (sbp, entityID, bssp, use_new_blast, fp, &errors_in_log);
4865   }
4866 
4867   FileClose (fp);
4868   if (errors_in_log > 0) {
4869     LaunchGeneralTextViewer (path, "Alignment Notes");
4870   }
4871   FileRemove (path);
4872   return OM_MSG_RET_DONE;
4873 }
4874 
4875 
GenerateSeqAlignMenuItem(IteM i)4876 extern void GenerateSeqAlignMenuItem (IteM i)
4877 {
4878   BaseFormPtr   bfp;
4879   SeqEntryPtr   sep;
4880 
4881 #ifdef WIN_MAC
4882   bfp = currentFormDataPtr;
4883 #else
4884   bfp = GetObjectExtra (i);
4885 #endif
4886   if (bfp == NULL) return;
4887 
4888   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
4889   if (sep == NULL || !IS_Bioseq_set (sep)) {
4890     Message (MSG_ERROR, "This record does not have a top-levelset!");
4891   } else {
4892     AddSeqAlignForSeqEntry (sep, bfp->input_entityID, FALSE, TRUE);
4893   }
4894 }
4895 
4896 static Int2 LIBCALLBACK
GenerateSeqAlignFromSeqEntryMasterOption(Pointer data,Boolean choose_master,Boolean use_new_blast)4897 GenerateSeqAlignFromSeqEntryMasterOption
4898 (Pointer data,
4899  Boolean choose_master,
4900  Boolean use_new_blast)
4901 
4902 {
4903   OMProcControlPtr  ompcp;
4904   SeqEntryPtr       sep;
4905   BioseqSetPtr      bssp = NULL;
4906 
4907   ompcp = (OMProcControlPtr) data;
4908   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
4909   switch (ompcp->input_itemtype) {
4910     case OBJ_BIOSEQ :
4911       Message (MSG_ERROR, "Must select BioseqSet to create alignment");
4912       return OM_MSG_RET_ERROR;
4913       break;
4914     case OBJ_BIOSEQSET :
4915       bssp = (BioseqSetPtr) ompcp->input_data;
4916       if (bssp == NULL) {
4917         Message (MSG_ERROR, "Must select BioseqSet to create alignment");
4918         return OM_MSG_RET_ERROR;
4919       }
4920       break;
4921     case 0 :
4922       return OM_MSG_RET_ERROR;
4923     default :
4924       return OM_MSG_RET_ERROR;
4925   }
4926   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
4927   sep = SeqMgrGetSeqEntryForData (ompcp->input_data);
4928   if (sep == NULL) return OM_MSG_RET_ERROR;
4929 
4930   return AddSeqAlignForSeqEntry (sep, ompcp->input_entityID, choose_master, use_new_blast);
4931 }
4932 
GenerateSeqAlignFromSeqEntryUseNewBlast(Pointer data)4933 static Int2 LIBCALLBACK GenerateSeqAlignFromSeqEntryUseNewBlast (Pointer data)
4934 
4935 {
4936   return GenerateSeqAlignFromSeqEntryMasterOption (data, FALSE, TRUE);
4937 }
4938 
GenerateSeqAlignFromSeqEntryChooseMasterUseNewBlast(Pointer data)4939 static Int2 LIBCALLBACK GenerateSeqAlignFromSeqEntryChooseMasterUseNewBlast (Pointer data)
4940 
4941 {
4942   return GenerateSeqAlignFromSeqEntryMasterOption (data, TRUE, TRUE);
4943 }
4944 
GenerateSeqAlignFromSeqEntryProtEx(Pointer data,Boolean use_new_blast)4945 static Int2 LIBCALLBACK GenerateSeqAlignFromSeqEntryProtEx (Pointer data, Boolean use_new_blast)
4946 
4947 {
4948   BioseqPtr         bsp;
4949   BioseqSetPtr      bssp;
4950   SeqAnnotPtr       curr;
4951   OMProcControlPtr  ompcp;
4952   SeqAlignPtr       salp;
4953   SeqAlignPtr       salp_head;
4954   SeqAlignPtr       salp_mult;
4955   SeqAlignPtr       salp_prev;
4956   SeqAlignPtr       salp_tmp;
4957   SeqAnnotPtr       sap;
4958   SeqAnnotPtr PNTR  sapp;
4959   SQNBspPtr         sbp;
4960   SQNBspPtr         sbp_prev;
4961   SeqEntryPtr       sep;
4962 
4963   ompcp = (OMProcControlPtr) data;
4964   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
4965   switch (ompcp->input_itemtype) {
4966     case OBJ_BIOSEQ :
4967       break;
4968     case OBJ_BIOSEQSET :
4969       break;
4970     case 0 :
4971       return OM_MSG_RET_ERROR;
4972     default :
4973       return OM_MSG_RET_ERROR;
4974   }
4975   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
4976   sep = SeqMgrGetSeqEntryForData (ompcp->input_data);
4977   if (sep == NULL) return OM_MSG_RET_ERROR;
4978   sbp = (SQNBspPtr)MemNew(sizeof(SQNBsp));
4979   SeqEntryExplore(sep, sbp, SQNGetBioseqsProt);
4980   bsp = sbp->bsp;
4981   sbp_prev = sbp;
4982   sbp = sbp->next;
4983   MemFree(sbp_prev);
4984   salp_head = salp_prev = NULL;
4985   while (sbp != NULL)
4986   {
4987     if (use_new_blast)
4988     {
4989       salp = Sequin_GlobalAlign2Seq(bsp, sbp->bsp, FALSE);
4990     }
4991     else
4992     {
4993       salp = Sqn_GlobalAlign2Seq(bsp, sbp->bsp, FALSE);
4994     }
4995     if (salp_head != NULL && salp != NULL)
4996     {
4997        salp_prev->next = salp;
4998        salp_prev = salp;
4999     } else if (salp != NULL)
5000        salp_head = salp_prev = salp;
5001     sbp_prev = sbp;
5002     sbp = sbp->next;
5003     MemFree(sbp_prev);
5004   }
5005   if (salp_head != NULL)
5006   {
5007     salp_tmp = salp_head;
5008     while (salp_tmp != NULL)
5009     {
5010        if (salp_tmp->saip != NULL)
5011        {
5012           SeqAlignIndexFree(salp_tmp->saip);
5013           salp_tmp->saip = NULL;
5014        }
5015        salp_tmp = salp_tmp->next;
5016     }
5017     AlnMgr2IndexSeqAlign(salp_head);
5018     salp_mult = AlnMgr2GetSubAlign(salp_head, 0, -1, 0, TRUE);
5019     salp_mult->dim = AlnMgr2GetNumRows(salp_head);
5020     salp_mult->type = SAT_PARTIAL;
5021     FixAlignmentEndStubs (salp_mult);
5022     SeqAlignSetFree(salp_head);
5023     sap = SeqAnnotForSeqAlign(salp_mult);
5024   } else
5025     sap = NULL;
5026   if (sap != NULL) {
5027 
5028     sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
5029     if (sep != NULL && sep->data.ptrvalue != NULL) {
5030       sapp = NULL;
5031       if (IS_Bioseq (sep)) {
5032         bsp = (BioseqPtr) sep->data.ptrvalue;
5033         sapp = &(bsp->annot);
5034       } else if (IS_Bioseq_set (sep)) {
5035         bssp = (BioseqSetPtr) sep->data.ptrvalue;
5036         sapp = &(bssp->annot);
5037       }
5038       if (sapp != NULL) {
5039         if (*sapp != NULL) {
5040           curr = *sapp;
5041           while (curr->next != NULL) {
5042             curr = curr->next;
5043           }
5044           curr->next = sap;
5045         } else {
5046           *sapp = sap;
5047         }
5048       }
5049       ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
5050       ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
5051     }
5052   }
5053   return OM_MSG_RET_DONE;
5054 }
5055 
5056 
GenerateSeqAlignFromSeqEntryProtUseNewBlast(Pointer data)5057 static Int2 LIBCALLBACK GenerateSeqAlignFromSeqEntryProtUseNewBlast (Pointer data)
5058 {
5059   return GenerateSeqAlignFromSeqEntryProtEx (data, TRUE);
5060 }
5061 
RawSeqLaunchFunc(GatherContextPtr gcp)5062 static Boolean RawSeqLaunchFunc (GatherContextPtr gcp)
5063 
5064 {
5065   BioseqPtr  bsp;
5066   Int2       handled;
5067 
5068   if (gcp == NULL) return TRUE;
5069   bsp = (BioseqPtr) gcp->userdata;
5070   if (bsp == NULL) return TRUE;
5071   if (gcp->thistype == OBJ_BIOSEQ) {
5072     if (bsp == (BioseqPtr) gcp->thisitem) {
5073       WatchCursor ();
5074       handled = GatherProcLaunch (OMPROC_EDIT, FALSE, gcp->entityID, gcp->itemID,
5075                                   OBJ_BIOSEQ, 0, 0, OBJ_BIOSEQ, 0);
5076       ArrowCursor ();
5077       if (handled != OM_MSG_RET_DONE || handled == OM_MSG_RET_NOPROC) {
5078         /*
5079         Message (MSG_ERROR, "Unable to launch editor on sequence.");
5080         */
5081       }
5082       return FALSE;
5083     }
5084   }
5085   return TRUE;
5086 }
5087 
BioseqSegEditFunc(Pointer data)5088 extern Int2 LIBCALLBACK BioseqSegEditFunc (Pointer data)
5089 
5090 {
5091   BioseqPtr         bsp;
5092   GatherScope       gs;
5093   SeqIdPtr          sip;
5094   SeqLocPtr         slp = NULL;
5095   OMProcControlPtr  ompcp;
5096 
5097   ompcp = (OMProcControlPtr) data;
5098   slp = NULL;
5099   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
5100   switch (ompcp->input_itemtype) {
5101     case OBJ_BIOSEQ_SEG :
5102       slp = (SeqLocPtr) ompcp->input_data;
5103       break;
5104    case 0 :
5105       return OM_MSG_RET_ERROR;
5106     default :
5107       return OM_MSG_RET_ERROR;
5108   }
5109   if (slp == NULL) return OM_MSG_RET_ERROR;
5110   sip = SeqLocId (slp);
5111   if (sip == NULL) return OM_MSG_RET_ERROR;
5112   bsp = BioseqFind (sip);
5113   if (bsp == NULL) return OM_MSG_RET_ERROR;
5114   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
5115   gs.seglevels = 1;
5116   gs.get_feats_location = TRUE;
5117   MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
5118   gs.ignore[OBJ_BIOSEQ] = FALSE;
5119   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
5120   GatherEntity (ompcp->input_entityID, (Pointer) bsp, RawSeqLaunchFunc, &gs);
5121 
5122   return OM_MSG_RET_DONE;
5123 }
5124 
SeqLocCopyOne(SeqLocPtr slp)5125 static SeqLocPtr SeqLocCopyOne (SeqLocPtr slp)
5126 {
5127   SeqLocPtr   slpnew, slptemp;
5128 
5129   slptemp = slp->next;
5130   slp->next = NULL;
5131   slpnew = AsnIoMemCopy ((Pointer) slp, (AsnReadFunc) SeqLocAsnRead,
5132                          (AsnWriteFunc) SeqLocAsnWrite);
5133   slp->next = slptemp;
5134   return slpnew;
5135 }
5136 
SeqFeatCopy(SeqFeatPtr sfp)5137 extern SeqFeatPtr SeqFeatCopy (SeqFeatPtr sfp)
5138 {
5139   SeqFeatPtr  sfpnew;
5140 
5141   sfpnew = AsnIoMemCopy ((Pointer) sfp, (AsnReadFunc) SeqFeatAsnRead,
5142                          (AsnWriteFunc) SeqFeatAsnWrite);
5143   return sfpnew;
5144 }
5145 
5146 static void
SetExplodedProtein(BioseqPtr orig_prot,BioseqSetPtr nucprot_bssp,BioseqPtr nucbsp,SeqFeatPtr sfp,CharPtr prot_id_str,Int4 cum_offset)5147 SetExplodedProtein
5148 (BioseqPtr    orig_prot,
5149  BioseqSetPtr nucprot_bssp,
5150  BioseqPtr    nucbsp,
5151  SeqFeatPtr   sfp,
5152  CharPtr      prot_id_str,
5153  Int4         cum_offset)
5154 {
5155   SeqIdPtr    prot_sip;
5156   BioseqPtr   new_prot;
5157   SeqEntryPtr prot_sep, sep_last;
5158   Int4        frame_shift, prot_start, prot_stop;
5159   Int4        loc_len, adjusted_len = 0, prot_len;
5160   CdRegionPtr crp;
5161   ValNodePtr  vnp;
5162   MolInfoPtr  mip;
5163   Boolean     partial5, partial3;
5164 
5165   if (orig_prot == NULL || nucprot_bssp == NULL
5166       || sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION
5167       || StringHasNoText (prot_id_str))
5168   {
5169     return;
5170   }
5171 
5172   crp = (CdRegionPtr) sfp->data.value.ptrvalue;
5173   if (crp == NULL)
5174   {
5175     return;
5176   }
5177 
5178   prot_sip = MakeUniqueSeqID (prot_id_str);
5179   frame_shift = cum_offset % 3;
5180   if (frame_shift == 0
5181       || (crp->frame == 3 && frame_shift == 1)
5182       || (crp->frame == 2 && frame_shift == 2))
5183   {
5184     prot_start = cum_offset / 3;
5185   }
5186   else
5187   {
5188     prot_start = cum_offset / 3 + 1;
5189   }
5190   loc_len = SeqLocLen (sfp->location);
5191   if (crp->frame == 1 || crp->frame == 0)
5192   {
5193     adjusted_len = loc_len - frame_shift;
5194   }
5195   else if (crp->frame == 2)
5196   {
5197     adjusted_len = loc_len - frame_shift - 1;
5198   }
5199   else if (crp->frame == 3)
5200   {
5201     adjusted_len = loc_len - frame_shift - 2;
5202   }
5203   prot_len = adjusted_len / 3;
5204   if (adjusted_len % 3 == 2)
5205   {
5206     prot_len ++;
5207   }
5208   prot_stop = prot_start + prot_len - 1;
5209   if (prot_stop > orig_prot->length - 1)
5210   {
5211     prot_stop = orig_prot->length - 1;
5212   }
5213   new_prot = BioseqCopyEx (prot_sip, orig_prot,
5214                            prot_start,
5215                            prot_stop,
5216                            Seq_strand_plus, TRUE);
5217   /* add to nuc-prot set */
5218   prot_sep = SeqEntryNew ();
5219   prot_sep->choice = 1;
5220   prot_sep->data.ptrvalue = new_prot;
5221   sep_last = nucprot_bssp->seq_set;
5222   while (sep_last != NULL && sep_last->next != NULL)
5223   {
5224     sep_last = sep_last->next;
5225   }
5226   if (sep_last == NULL)
5227   {
5228     nucprot_bssp->seq_set = prot_sep;
5229   }
5230   else
5231   {
5232     sep_last->next = prot_sep;
5233   }
5234 
5235   SeqMgrAddToBioseqIndex (new_prot);
5236 
5237   /* set partials */
5238   CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
5239   if (cum_offset > 0)
5240   {
5241     partial5 = TRUE;
5242   }
5243   if (prot_stop < orig_prot->length - 1)
5244   {
5245     partial3 = TRUE;
5246   }
5247   SetSeqLocPartial (sfp->location, partial5, partial3);
5248   sfp->partial = partial5 || partial3;
5249 
5250   /* add MolInfo descriptor */
5251   vnp = SeqEntryGetSeqDescr (prot_sep, Seq_descr_molinfo, NULL);
5252   if (vnp == NULL) {
5253     vnp = CreateNewDescriptor (prot_sep, Seq_descr_molinfo);
5254   }
5255   if (vnp != NULL)
5256   {
5257     mip = (MolInfoPtr) vnp->data.ptrvalue;
5258     if (mip == NULL)
5259     {
5260       mip = MolInfoNew ();
5261       vnp->data.ptrvalue = (Pointer) mip;
5262     }
5263     if (mip != NULL) {
5264       mip->biomol = 8;
5265       mip->tech = 13;
5266       if (partial5 && partial3) {
5267         mip->completeness = 5;
5268       } else if (partial5) {
5269         mip->completeness = 3;
5270       } else if (partial3) {
5271         mip->completeness = 4;
5272       } else {
5273         mip->completeness = 0;
5274       }
5275     }
5276   }
5277 
5278   /* make feature product point to new Bioseq */
5279   sfp->product = ValNodeNew (NULL);
5280   sfp->product->choice = SEQLOC_WHOLE;
5281   sfp->product->data.ptrvalue = prot_sip;
5282 
5283   /* adjust frame */
5284   if (frame_shift != 0)
5285   {
5286     switch (crp->frame)
5287     {
5288       case 0:
5289       case 1:
5290         if (frame_shift == 1)
5291         {
5292           crp->frame = 3;
5293         }
5294         else if (frame_shift == 2)
5295         {
5296           crp->frame = 2;
5297         }
5298         break;
5299       case 2:
5300         if (frame_shift == 1)
5301         {
5302           crp->frame = 1;
5303         }
5304         else if (frame_shift == 2)
5305         {
5306           crp->frame = 3;
5307         }
5308         break;
5309       case 3:
5310         if (frame_shift == 1)
5311         {
5312           crp->frame = 2;
5313         }
5314         else if (frame_shift == 2)
5315         {
5316           crp->frame = 1;
5317         }
5318         break;
5319     }
5320   }
5321 
5322   /* retranslate coding region */
5323   SeqEdTranslateOneCDS (sfp, nucbsp, nucbsp->idx.entityID, Sequin_GlobalAlign2Seq);
5324 }
5325 
ObjectIdFromString(CharPtr str)5326 static ObjectIdPtr ObjectIdFromString (CharPtr str)
5327 {
5328   CharPtr cp;
5329   ObjectIdPtr oip;
5330 
5331   oip = ObjectIdNew ();
5332 
5333   if (!StringHasNoText (str)) {
5334     cp = str;
5335     while (*cp != 0 && isdigit (*cp)) {
5336       cp++;
5337     }
5338     if (*cp == 0) {
5339       oip->id = atoi (str);
5340     } else {
5341       oip->str = StringSave (str);
5342     }
5343   }
5344   return oip;
5345 }
5346 
5347 
IncrementObjectId(ObjectIdPtr oip)5348 static void IncrementObjectId (ObjectIdPtr oip)
5349 {
5350   Int4 len;
5351 
5352   if (oip == NULL) {
5353     return;
5354   }
5355 
5356   if (!StringHasNoText (oip->str)) {
5357     len = StringLen (oip->str);
5358     *(oip->str + len - 1) = *(oip->str + len - 1) + 1;
5359   } else {
5360     oip->id++;
5361   }
5362 
5363 }
5364 
5365 
DecrementObjectId(ObjectIdPtr oip)5366 static void DecrementObjectId (ObjectIdPtr oip)
5367 {
5368   Int4 len;
5369 
5370   if (oip == NULL) {
5371     return;
5372   }
5373 
5374   if (!StringHasNoText (oip->str)) {
5375     len = StringLen (oip->str);
5376     *(oip->str + len - 1) = *(oip->str + len - 1) - 1;
5377   } else {
5378     oip->id--;
5379   }
5380 
5381 }
5382 
5383 
ObjectIdLabel(ObjectIdPtr oip)5384 static CharPtr ObjectIdLabel (ObjectIdPtr oip)
5385 {
5386   Char buf[15];
5387 
5388   if (oip == NULL) {
5389     return NULL;
5390   }
5391   if (!StringHasNoText (oip->str)) {
5392     return StringSave (oip->str);
5393   } else {
5394     sprintf (buf, "%d", oip->id);
5395     return StringSave (buf);
5396   }
5397 }
5398 
5399 
ExplodeGroup(SeqEntryPtr sep,SeqFeatPtr sfp)5400 static Boolean ExplodeGroup (SeqEntryPtr sep, SeqFeatPtr sfp)
5401 
5402 {
5403   SeqFeatPtr     sfpnew, sfpold, sfplast;
5404   ImpFeatPtr     ifp;
5405   SeqLocPtr      slphead, slp;
5406   GBQualPtr      gbq;
5407   ObjectIdPtr    exon_count = NULL;
5408   BioseqPtr      orig_prot = NULL, nucbsp;
5409   Int4           cum_offset = 0;
5410   Char           prot_id_str [128];
5411   Char           prot_id_str_prefix [255];
5412   SeqEntryPtr    nucprot_sep = NULL;
5413   BioseqSetPtr   nucprot_bssp = NULL;
5414   ObjMgrDataPtr  omdptop;
5415   ObjMgrData     omdata;
5416   Uint2          parenttype;
5417   Pointer        parentptr;
5418   Int4           feat_num = 1;
5419 
5420   if (sfp == NULL || sfp->location == NULL) return FALSE;
5421 
5422 /* save the seqloc (chain) */
5423   slphead = sfp->location;
5424   slp = SeqLocFindNext (slphead, NULL);
5425   if (slp == NULL) return FALSE;
5426 
5427 /* trash the loc info in the impfeat */
5428   if (sfp->data.choice == SEQFEAT_IMP) {
5429     ifp = (ImpFeatPtr) sfp->data.value.ptrvalue;
5430     if (ifp != NULL) {
5431       ifp->loc = MemFree (ifp->loc);
5432     }
5433   }
5434 
5435   /* if coding region, get copy of original protein, to use when
5436    * retranslating coding regions
5437    */
5438   if (sfp->data.choice == SEQFEAT_CDREGION && sfp->product != NULL)
5439   {
5440     orig_prot = BioseqFindFromSeqLoc (sfp->product);
5441     if (orig_prot != NULL)
5442     {
5443       nucbsp = BioseqFindFromSeqLoc (sfp->location);
5444       if (nucbsp != NULL)
5445       {
5446         nucprot_sep = GetBestTopParentForData (nucbsp->idx.entityID, nucbsp);
5447         if (nucprot_sep != NULL && IS_Bioseq_set (nucprot_sep))
5448         {
5449           nucprot_bssp = (BioseqSetPtr) nucprot_sep->data.ptrvalue;
5450           if (nucprot_bssp != NULL
5451               && nucprot_bssp->_class == BioseqseqSet_class_nuc_prot)
5452           {
5453             sfp->product = NULL;
5454             SeqIdWrite (SeqIdFindBest (orig_prot->id, SEQID_LOCAL), prot_id_str,
5455                         PRINTID_REPORT, sizeof (prot_id_str) - 1);
5456           }
5457         }
5458       }
5459       if (nucprot_bssp == NULL)
5460       {
5461         orig_prot = NULL;
5462       }
5463       else
5464       {
5465         SaveSeqEntryObjMgrData (nucprot_sep, &omdptop, &omdata);
5466         GetSeqEntryParent (nucprot_sep, &parentptr, &parenttype);
5467       }
5468     }
5469   }
5470 
5471 
5472 /* orig sfp is copied then orig sfp data is replaced */
5473   sfplast = sfp->next;
5474   sfpnew = SeqFeatCopy (sfp);
5475 
5476 /* if exon, increment /number qualifier */
5477   gbq = NULL;
5478   if (sfpnew != NULL && sfpnew->data.choice == SEQFEAT_IMP) {
5479     ifp = (ImpFeatPtr) sfpnew->data.value.ptrvalue;
5480     if (ifp != NULL) {
5481       if (StringICmp (ifp->key, "exon") == 0) {
5482         gbq = sfpnew->qual;
5483         while (gbq != NULL && StringICmp (gbq->qual, "number") != 0) {
5484           gbq = gbq->next;
5485         }
5486         if (gbq != NULL) {
5487           exon_count = ObjectIdFromString (gbq->val);
5488         }
5489       }
5490     }
5491   }
5492 
5493   sfp->location = SeqLocCopyOne (slp);
5494   if (sfp->data.choice == SEQFEAT_CDREGION && orig_prot != NULL)
5495   {
5496     sprintf (prot_id_str_prefix, "%s%d", prot_id_str, feat_num);
5497     SetExplodedProtein (orig_prot, nucprot_bssp, nucbsp, sfp, prot_id_str_prefix, cum_offset);
5498     /* adjust cum_offset */
5499     cum_offset += SeqLocLen (sfp->location);
5500     feat_num++;
5501   }
5502   sfpold = sfp;
5503   slp = SeqLocFindNext (slphead, slp);
5504 
5505 /* clone as many more as required */
5506   while (slp != NULL) {
5507     if (slp->choice != SEQLOC_NULL) {
5508       if (gbq != NULL) {
5509         gbq->val = MemFree (gbq->val);
5510         IncrementObjectId (exon_count);
5511         gbq->val = ObjectIdLabel (exon_count);
5512       }
5513       sfp = SeqFeatCopy (sfpnew);
5514       sfp->location = SeqLocFree (sfp->location);
5515       sfp->location = SeqLocCopyOne (slp);
5516       sfp->partial = CheckSeqLocForPartial (sfp->location, NULL, NULL);
5517 
5518       if (sfp->data.choice == SEQFEAT_CDREGION && orig_prot != NULL)
5519       {
5520         sprintf (prot_id_str_prefix, "%s%d", prot_id_str, feat_num);
5521         SetExplodedProtein (orig_prot, nucprot_bssp, nucbsp, sfp, prot_id_str_prefix, cum_offset);
5522         /* adjust cum_offset */
5523         cum_offset += SeqLocLen (sfp->location);
5524         feat_num++;
5525       }
5526 
5527       sfpold->next = sfp;
5528       sfpold = sfp;
5529     }
5530     slp = SeqLocFindNext (slphead, slp);
5531   }
5532   sfpold->next = sfplast;
5533   sfpnew = SeqFeatFree (sfpnew);
5534   slphead = SeqLocFree (slphead);
5535 
5536   if (orig_prot != NULL)
5537   {
5538     /* mark orig_prot for deletion */
5539     orig_prot->idx.deleteme = TRUE;
5540 
5541     /* relink nucprot set parent */
5542     SeqMgrLinkSeqEntry (nucprot_sep, parenttype, parentptr);
5543     RestoreSeqEntryObjMgrData (nucprot_sep, omdptop, &omdata);
5544   }
5545 
5546   return TRUE;
5547 }
5548 
GroupExplodeFunc(Pointer data)5549 static Int2 LIBCALLBACK GroupExplodeFunc (Pointer data)
5550 
5551 {
5552   OMProcControlPtr  ompcp;
5553   SelStructPtr      ssp;
5554   Boolean           isDirty = FALSE;
5555   Boolean           isFirstSsp;
5556   ExplodeStructPtr  esp;
5557   ExplodeStructPtr  firstEsp = NULL;
5558   ExplodeStructPtr  lastEsp;
5559   Boolean           isFirstEsp;
5560 
5561   /* Check the parameter */
5562 
5563   ompcp = (OMProcControlPtr) data;
5564   if (ompcp == NULL || ompcp->input_itemtype == 0)
5565     return OM_MSG_RET_ERROR;
5566 
5567   /* Get the linked of list of selected items */
5568 
5569   ssp  = ObjMgrGetSelected();
5570 
5571   /* Go through the list and save pointers */
5572   /* to the items themselves.              */
5573 
5574   isFirstEsp = TRUE;
5575   isFirstSsp = TRUE;
5576 
5577   while (NULL != ssp) {
5578 
5579     if (!isFirstSsp) {
5580       ompcp->input_entityID = ssp->entityID;
5581       ompcp->input_itemID   = ssp->itemID;
5582       ompcp->input_itemtype = ssp->itemtype;
5583 
5584       GatherDataForProc (ompcp, FALSE);
5585     }
5586 
5587     switch (ssp->itemtype)
5588       {
5589       case OBJ_SEQFEAT:
5590 
5591 	esp = (ExplodeStructPtr) MemNew (sizeof (ExplodeStruct));
5592 	esp->seqFeatPtr = (SeqFeatPtr) ompcp->input_data;
5593 	esp->topSep     = GetTopSeqEntryForEntityID (ssp->entityID);
5594 
5595 	if (isFirstEsp) {
5596 	  firstEsp = esp;
5597 	  isFirstEsp = FALSE;
5598 	}
5599 	else
5600 	  lastEsp->next = esp;
5601 
5602 	lastEsp = esp;
5603 	lastEsp->next = NULL;
5604 	break;
5605       default:
5606 	break;
5607       }
5608 
5609     isFirstSsp = FALSE;
5610     ssp = ssp->next;
5611   }
5612 
5613   /* Loop through all the selected items */
5614   /* and explode each one.               */
5615 
5616   esp = firstEsp;
5617   while (NULL != esp) {
5618     if (ExplodeGroup (esp->topSep, esp->seqFeatPtr))
5619       isDirty = TRUE;
5620     esp = esp->next;
5621   }
5622 
5623   /* If any actual exploding was done then */
5624   /* force an update to be done.           */
5625 
5626   if (isDirty)
5627     {
5628       /* remove any protein sequences that were marked for deletion */
5629       DeleteMarkedObjects (ompcp->input_entityID, 0, NULL);
5630 
5631       ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
5632       ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID,
5633 		     ompcp->input_itemID, ompcp->input_itemtype);
5634       return OM_MSG_RET_DONE;
5635     }
5636   else
5637     return OM_MSG_RET_ERROR;
5638 }
5639 
5640 
SortVnpByInt(VoidPtr ptr1,VoidPtr ptr2)5641 static int LIBCALLBACK SortVnpByInt (VoidPtr ptr1, VoidPtr ptr2)
5642 
5643 {
5644   ValNodePtr  vnp1;
5645   ValNodePtr  vnp2;
5646 
5647   if (ptr1 == NULL || ptr2 == NULL) return 0;
5648   vnp1 = *((ValNodePtr PNTR) ptr1);
5649   vnp2 = *((ValNodePtr PNTR) ptr2);
5650   if (vnp1 == NULL || vnp2 == NULL) return 0;
5651 
5652   if (vnp1->data.intvalue > vnp2->data.intvalue) {
5653     return 1;
5654   } else if (vnp1->data.intvalue < vnp2->data.intvalue) {
5655     return -1;
5656   }
5657 
5658   return 0;
5659 }
5660 
GroupExplode()5661 static void GroupExplode()
5662 {
5663   ValNodePtr        entityIDList = NULL, vnp;
5664   SelStructPtr      ssp;
5665   Boolean           isDirty = FALSE;
5666   SeqEntryPtr       sep;
5667   SeqFeatPtr        sfp;
5668   SeqMgrFeatContext context;
5669 
5670   ssp  = ObjMgrGetSelected();
5671   if (ssp == NULL) {
5672     Message (MSG_ERROR, "Nothing selected!");
5673     return;
5674   }
5675   while (NULL != ssp) {
5676     if (ssp->itemtype == OBJ_SEQFEAT)
5677     {
5678       sep = GetTopSeqEntryForEntityID (ssp->entityID);
5679 
5680       sfp = SeqMgrGetDesiredFeature (ssp->entityID, NULL, ssp->itemID, 0, NULL, &context);
5681       if (sfp != NULL && ExplodeGroup (sep, sfp))
5682       {
5683         isDirty = TRUE;
5684         ValNodeAddInt (&entityIDList, 0, ssp->entityID);
5685       }
5686     }
5687     ssp = ssp->next;
5688   }
5689 
5690   /* If any actual exploding was done then */
5691   /* force an update to be done.           */
5692 
5693   if (isDirty)
5694   {
5695     entityIDList = ValNodeSort (entityIDList, SortVnpByInt);
5696     ValNodeUnique (&entityIDList, SortVnpByInt, ValNodeFree);
5697     for (vnp = entityIDList; vnp != NULL; vnp = vnp->next) {
5698       /* remove any protein sequences that were marked for deletion */
5699       DeleteMarkedObjects (vnp->data.intvalue, 0, NULL);
5700       ObjMgrSetDirtyFlag (vnp->data.intvalue, TRUE);
5701       ObjMgrSendMsg (OM_MSG_UPDATE, vnp->data.intvalue, 0, 0);
5702     }
5703     entityIDList = ValNodeFree (entityIDList);
5704   }
5705 }
5706 
5707 
GroupExplodeMenuItem(IteM i)5708 extern void GroupExplodeMenuItem (IteM i)
5709 {
5710   GroupExplode();
5711 }
5712 
5713 
GroupExplodeToolBtn(ButtoN b)5714 extern void GroupExplodeToolBtn (ButtoN b)
5715 {
5716   GroupExplode();
5717 }
5718 
5719 
5720 static SeqFeatPtr
AddIntronForInterval(Int4 start,Int4 stop,Int4 last,Uint1 strand,BioseqPtr bsp,Int2 fuzz_from,Int2 fuzz_to,ObjectIdPtr part_number)5721 AddIntronForInterval
5722 (Int4 start,
5723  Int4 stop,
5724  Int4 last,
5725  Uint1 strand,
5726  BioseqPtr bsp,
5727  Int2 fuzz_from,
5728  Int2 fuzz_to,
5729  ObjectIdPtr part_number)
5730 {
5731   SeqFeatPtr sfp;
5732   ImpFeatPtr ifp;
5733   GBQualPtr  gbqual;
5734   Int4 int_from, int_to;
5735 
5736   if (strand == Seq_strand_minus) {
5737     int_from = stop + 1;
5738     int_to = last - 1;
5739   } else {
5740     int_from = last + 1;
5741     int_to = start - 1;
5742   }
5743   if (int_from > int_to) {
5744     return NULL;
5745   }
5746   if (int_from == 0) {
5747     fuzz_from = 2;
5748   }
5749   if (int_to == bsp->length - 1) {
5750     fuzz_to = 1;
5751   }
5752 
5753   sfp = SeqFeatNew ();
5754   if (sfp == NULL) {
5755     return NULL;
5756   }
5757 
5758   sfp->data.choice = SEQFEAT_IMP;
5759   AddIntToSeqFeat (sfp, int_from, int_to, bsp,
5760                      fuzz_from, fuzz_to, strand);
5761 
5762   ifp = ImpFeatNew ();
5763   if (ifp != NULL) {
5764     sfp->data.value.ptrvalue = (Pointer) ifp;
5765     ifp->key = StringSave ("intron");
5766   }
5767   gbqual = GBQualNew ();
5768   if (gbqual != NULL)
5769   {
5770     /* need to use the previous value */
5771     DecrementObjectId (part_number);
5772     gbqual->qual = StringSave ("number");
5773     gbqual->val = ObjectIdLabel (part_number);
5774     /* put back to original value */
5775     IncrementObjectId (part_number);
5776     gbqual->next = sfp->qual;
5777     sfp->qual = gbqual;
5778   }
5779   return sfp;
5780 }
5781 
MakeExonsAndIntronsFromFeature(SeqEntryPtr sep,BioseqPtr bsp,SeqLocPtr location,SeqFeatPtr putafterhere,Boolean MakeIntrons,ObjectIdPtr first_exon_number)5782 static Boolean MakeExonsAndIntronsFromFeature (SeqEntryPtr sep, BioseqPtr bsp,
5783                                                SeqLocPtr location,
5784                                                SeqFeatPtr putafterhere,
5785                                                Boolean MakeIntrons,
5786                                                ObjectIdPtr first_exon_number)
5787 
5788 {
5789   SeqFeatPtr  curr;
5790   Boolean     first;
5791   Int2        fuzz_from;
5792   Int2        fuzz_to;
5793   ImpFeatPtr  ifp;
5794   Int4        last;
5795   SeqLocPtr   next;
5796   SeqFeatPtr  putbeforehere;
5797   SeqFeatPtr  sfp, intron;
5798   SeqLocPtr   slp;
5799   Int4        start;
5800   Int4        stop;
5801   Uint1       strand;
5802   Int4        tmp;
5803   Boolean     partial5, partial3, first_partial, last_partial;
5804   GBQualPtr   gbqual;
5805   ObjectIdPtr part_number;
5806   ValNodePtr  merge_to_parts_list = NULL;
5807   ValNodePtr  vnp;
5808 
5809   if (sep == NULL || bsp == NULL || location == NULL || putafterhere == NULL) return FALSE;
5810   putbeforehere = putafterhere->next;
5811   curr = putafterhere;
5812   slp = SeqLocFindNext (location, NULL);
5813   if (slp == NULL) return FALSE;
5814   first = TRUE;
5815   last = 0;
5816   part_number = ObjectIdDup (first_exon_number);
5817   CheckSeqLocForPartial (location, &first_partial, &last_partial);
5818   while (slp != NULL) {
5819     CheckSeqLocForPartial (slp, &partial5, &partial3);
5820     next = SeqLocFindNext (location, slp);
5821     if (slp->choice != SEQLOC_NULL) {
5822       start = GetOffsetInBioseq (slp, bsp, SEQLOC_START);
5823       stop = GetOffsetInBioseq (slp, bsp, SEQLOC_STOP);
5824       strand = SeqLocStrand (slp);
5825       if (strand > Seq_strand_both_rev && strand != Seq_strand_other) {
5826         strand = Seq_strand_unknown;
5827       }
5828       fuzz_from = -1;
5829       fuzz_to = -1;
5830       if (start > stop) {
5831         tmp = start;
5832         start = stop;
5833         stop = tmp;
5834       }
5835       if (start != 0) {
5836         if (strand == Seq_strand_minus) {
5837           partial3 = FALSE;
5838         } else {
5839           partial5 = FALSE;
5840         }
5841       }
5842       if (stop != bsp->length - 1) {
5843         if (strand == Seq_strand_minus) {
5844           partial5 = FALSE;
5845         } else {
5846           partial3 = FALSE;
5847         }
5848       }
5849       if (MakeIntrons) {
5850         intron = NULL;
5851         if (!first) {
5852           intron = AddIntronForInterval (start, stop, last, strand, bsp, fuzz_from, fuzz_to, part_number);
5853         } else if (first_partial) {
5854           if (strand == Seq_strand_minus) {
5855             intron = AddIntronForInterval (start, stop, bsp->length, strand, bsp, fuzz_from, fuzz_to, part_number);
5856           } else {
5857             intron = AddIntronForInterval (start, stop, -1, strand, bsp, fuzz_from, fuzz_to, part_number);
5858           }
5859         }
5860         if (intron != NULL) {
5861           if (bsp->repr == Seq_repr_seg)
5862           {
5863             ValNodeAddPointer (&merge_to_parts_list, 0, intron);
5864           }
5865           curr->next = intron;
5866           curr = intron;
5867         }
5868       }
5869       first = FALSE;
5870       if (strand == Seq_strand_minus) {
5871         last = start;
5872       } else {
5873         last = stop;
5874       }
5875       sfp = SeqFeatNew ();
5876       if (sfp != NULL) {
5877         sfp->data.choice = SEQFEAT_IMP;
5878         AddIntToSeqFeat (sfp, start, stop, bsp,
5879                          fuzz_from, fuzz_to, strand);
5880         ifp = ImpFeatNew ();
5881         if (ifp != NULL) {
5882           sfp->data.value.ptrvalue = (Pointer) ifp;
5883           ifp->key = StringSave ("exon");
5884         }
5885         SetSeqLocPartial (sfp->location, partial5, partial3);
5886         gbqual = GBQualNew ();
5887         if (gbqual != NULL)
5888         {
5889           gbqual->qual = StringSave ("number");
5890           gbqual->val = ObjectIdLabel (part_number);
5891           gbqual->next = sfp->qual;
5892           sfp->qual = gbqual;
5893         }
5894         IncrementObjectId (part_number);
5895         if (bsp->repr == Seq_repr_seg)
5896         {
5897           ValNodeAddPointer (&merge_to_parts_list, 0, sfp);
5898         }
5899         curr->next = sfp;
5900         curr = sfp;
5901       }
5902     }
5903     slp = next;
5904   }
5905   if (MakeIntrons && last_partial) {
5906     intron = NULL;
5907     if (strand == Seq_strand_minus) {
5908       intron = AddIntronForInterval (start, -1, last, strand, bsp, fuzz_from, fuzz_to, part_number);
5909     } else {
5910       intron = AddIntronForInterval (bsp->length, stop, last, strand, bsp, fuzz_from, fuzz_to, part_number);
5911     }
5912     if (intron != NULL) {
5913       if (bsp->repr == Seq_repr_seg)
5914       {
5915         ValNodeAddPointer (&merge_to_parts_list, 0, intron);
5916       }
5917       curr->next = intron;
5918       curr = intron;
5919     }
5920   }
5921 
5922   curr->next = putbeforehere;
5923 
5924   for (vnp = merge_to_parts_list; vnp != NULL; vnp = vnp->next)
5925   {
5926     sfp = vnp->data.ptrvalue;
5927     MergeFeatureIntervalsToParts (sfp, FALSE);
5928   }
5929   ValNodeFree (merge_to_parts_list);
5930 
5931   part_number = ObjectIdFree (part_number);
5932 
5933   return TRUE;
5934 }
5935 
5936 
5937 typedef struct makeexondata {
5938   FEATURE_FORM_BLOCK
5939 
5940   ButtoN      make_introns_button;
5941   TexT        exon_number_field;
5942   DialoG      constraint_dlg;
5943   ButtoN      accept;
5944 
5945   SeqEntryPtr sep;
5946   Boolean     make_introns;
5947   ObjectIdPtr first_exon_number;
5948   Uint1       feature_type;
5949   ConstraintChoiceSetPtr constraint;
5950 } MakeExonData, PNTR MakeExonPtr;
5951 
MakeExonsFromFeatureIntervalsVisitFunc(SeqFeatPtr sfp,Pointer userdata)5952 static void MakeExonsFromFeatureIntervalsVisitFunc (SeqFeatPtr sfp, Pointer userdata)
5953 {
5954   MakeExonPtr mep;
5955   BioseqPtr   bsp;
5956 
5957   if (sfp == NULL || (mep = (MakeExonPtr) userdata) == NULL
5958       || sfp->idx.subtype != mep->feature_type
5959       || !DoesObjectMatchConstraintChoiceSet(OBJ_SEQFEAT, sfp, mep->constraint))
5960   {
5961     return;
5962   }
5963 
5964   mep = (MakeExonPtr) userdata;
5965   bsp = BioseqFindFromSeqLoc (sfp->location);
5966 
5967   MakeExonsAndIntronsFromFeature (mep->sep, bsp, sfp->location, sfp,
5968       mep->make_introns, mep->first_exon_number);
5969 
5970 }
5971 
5972 
DoMakeExonsFromFeatureIntervals(ButtoN b)5973 static void DoMakeExonsFromFeatureIntervals (ButtoN b)
5974 {
5975   MakeExonPtr mep;
5976   Char        exon_number_str [256];
5977 
5978   if (b == NULL || (mep = (MakeExonPtr) GetObjectExtra (b)) == NULL) return;
5979 
5980   Hide (mep->form);
5981 
5982   WatchCursor ();
5983   Update ();
5984 
5985   mep->sep = GetTopSeqEntryForEntityID (mep->input_entityID);
5986   mep->make_introns = GetStatus (mep->make_introns_button);
5987   GetTitle (mep->exon_number_field,
5988             exon_number_str,
5989             sizeof (exon_number_str) - 1 );
5990 
5991   mep->first_exon_number = ObjectIdFromString (exon_number_str);
5992   mep->constraint = DialogToPointer (mep->constraint_dlg);
5993 
5994   VisitFeaturesInSep (mep->sep, mep,
5995                       MakeExonsFromFeatureIntervalsVisitFunc);
5996   mep->first_exon_number = ObjectIdFree (mep->first_exon_number);
5997   mep->constraint = ConstraintChoiceSetFree (mep->constraint);
5998   ObjMgrSetDirtyFlag (mep->input_entityID, TRUE);
5999   ObjMgrSendMsg (OM_MSG_UPDATE, mep->input_entityID, 0, 0);
6000   ArrowCursor ();
6001   Update ();
6002 }
6003 
CheckExonNumberText(TexT number_field)6004 static void CheckExonNumberText (TexT number_field)
6005 {
6006   MakeExonPtr mep;
6007 
6008   if (number_field == NULL || (mep = (MakeExonPtr)GetObjectExtra (number_field)) == NULL) return;
6009   if (TextHasNoText (number_field)) {
6010     Disable (mep->accept);
6011   } else {
6012     Enable (mep->accept);
6013   }
6014 }
6015 
CommonMakeExonsFromFeatureIntervals(IteM i,Boolean make_introns,Uint1 feature_type)6016 static void CommonMakeExonsFromFeatureIntervals (
6017   IteM i,
6018   Boolean make_introns,
6019   Uint1 feature_type
6020 )
6021 {
6022   BaseFormPtr  bfp;
6023   MakeExonPtr  mep;
6024   WindoW       w;
6025   GrouP        h, p, c;
6026 
6027 #ifdef WIN_MAC
6028   bfp = currentFormDataPtr;
6029 #else
6030   bfp = GetObjectExtra (i);
6031 #endif
6032 
6033   if (bfp == NULL) return;
6034 
6035   mep = MemNew (sizeof (MakeExonData));
6036   if (mep == NULL) return;
6037   mep->input_entityID = bfp->input_entityID;
6038   mep->feature_type = feature_type;
6039 
6040   if (feature_type == FEATDEF_CDS)
6041   {
6042     w = FixedWindow (-50, -33, -10, -10, "Make Exons from CDS", NULL);
6043   }
6044   else if (feature_type == FEATDEF_mRNA)
6045   {
6046     w = FixedWindow (-50, -33, -10, -10, "Make Exons from mRNA", NULL);
6047   }
6048   else
6049   {
6050     w = FixedWindow (-50, -33, -10, -10, "Make Exons from Feature", NULL);
6051   }
6052 
6053   SetObjectExtra (w, mep, StdCleanupFormProc);
6054   mep->form = (ForM) w;
6055 
6056   h = HiddenGroup (w, -1, 0, NULL);
6057   SetGroupSpacing (h, 10, 10);
6058 
6059   p = HiddenGroup (h, 2, 0, NULL);
6060   StaticPrompt (p, "First Exon Number", 0, 0, programFont, 'c');
6061   mep->exon_number_field = DialogText (p, "1", 3, CheckExonNumberText);
6062   SetObjectExtra (mep->exon_number_field, mep, NULL);
6063   mep->make_introns_button = CheckBox (p, "Make Introns", NULL);
6064   mep->constraint_dlg = ComplexConstraintDialog(h, NULL, NULL);
6065   ChangeComplexConstraintFieldType(mep->constraint_dlg, FieldType_cds_gene_prot, NULL, Macro_feature_type_any);
6066 
6067   c = HiddenGroup (h, 4, 0, NULL);
6068   mep->accept = DefaultButton (c, "Accept", DoMakeExonsFromFeatureIntervals);
6069   SetObjectExtra (mep->accept, mep, NULL);
6070   PushButton (c, "Cancel", StdCancelButtonProc);
6071   AlignObjects (ALIGN_CENTER, (HANDLE) p, (HANDLE) mep->constraint_dlg, (HANDLE) c, NULL);
6072   RealizeWindow (w);
6073   Show (w);
6074   Update ();
6075 }
6076 
MakeExonsFromCDSIntervals(IteM i)6077 extern void MakeExonsFromCDSIntervals (IteM i)
6078 {
6079   CommonMakeExonsFromFeatureIntervals (i, FALSE, FEATDEF_CDS);
6080 }
6081 
MakeExonsFromMRNAIntervals(IteM i)6082 extern void MakeExonsFromMRNAIntervals (IteM i)
6083 {
6084   CommonMakeExonsFromFeatureIntervals (i, TRUE, FEATDEF_mRNA);
6085 }
6086 
6087 
DetachBioseq(Pointer data)6088 static Int2 LIBCALLBACK DetachBioseq (Pointer data)
6089 
6090 {
6091   BioseqPtr         bsp;
6092   BioseqSetPtr      bssp;
6093   OMProcControlPtr  ompcp;
6094   SeqEntryPtr       sep;
6095 
6096   ompcp = (OMProcControlPtr) data;
6097   if (ompcp == NULL || ompcp->input_itemtype == 0 || ompcp->input_data == NULL)
6098     return OM_MSG_RET_ERROR;
6099 
6100   switch (ompcp->input_itemtype)
6101   {
6102     case OBJ_BIOSEQ:
6103       bsp = (BioseqPtr) ompcp->input_data;
6104       if (bsp != NULL) {
6105         sep = bsp->seqentry;
6106         if (sep != NULL) {
6107           sep->next = NULL;
6108           ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
6109           ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, ompcp->input_itemID, ompcp->input_itemtype);
6110           return OM_MSG_RET_DONE;
6111         }
6112       }
6113       break;
6114     case OBJ_BIOSEQSET:
6115       bssp = (BioseqSetPtr) ompcp->input_data;
6116       if (bssp != NULL) {
6117         sep = bssp->seqentry;
6118         if (sep != NULL) {
6119           sep->next = NULL;
6120           ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
6121           ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, ompcp->input_itemID, ompcp->input_itemtype);
6122           return OM_MSG_RET_DONE;
6123         }
6124       }
6125       break;
6126     default:
6127       return OM_MSG_RET_ERROR;
6128   }
6129 
6130   return OM_MSG_RET_ERROR;
6131 }
6132 
6133 
6134 #define BLACK     0
6135 #define RED       4
6136 #define GREEN     2
6137 #define BLUE      1
6138 #define CYAN      3
6139 #define MAGENTA   5
6140 #define YELLOW    6
6141 #define WHITE    15
6142 #define GRAY      8
6143 #define LTGRAY    7
6144 
6145 #define DKCYAN   21
6146 #define DKGREEN  22
6147 #define DKBLUE  23
6148 
6149 #define ORF_LENGTH 10
6150 
6151 
6152 typedef struct orfviewform
6153 {
6154 	FORM_MESSAGE_BLOCK
6155 	IcoN 		icon;
6156 	WindoW 		w;
6157 	DoC 		doc;   /* orf list doc */
6158 	BioseqPtr	bsp;
6159 	Int2		gcode;
6160 	ValNodePtr	orfs;
6161 	Int2 		frame, strand;
6162 	Int4 		from, to;
6163 	double 		dx, dy;
6164 	RecT		mi;
6165 	Boolean		orf_only;
6166 	SeqLocPtr	select_orf;
6167 	Uint2 		bsp_entityID;
6168 	Uint4 		bsp_itemID;
6169 	Uint2 		len;		/* minimum length of the ORF shown */
6170 	Boolean     standAlone;
6171 	Boolean     alt_start;
6172   ParData     par; /* pardata for orf list doc */
6173   GrouP       orf_order;
6174   GrouP       start_choice;
6175   ButtoN      show_partial_btn;
6176   Boolean     allow_partial;
6177 } OrfViewForm, PNTR OrfViewFormPtr;
6178 
6179 static RecT mi0 = {  24,  56, 460, 200 };
6180 
6181 Uint1 AAForCodon (Uint1Ptr codon, CharPtr codes); /* in seqport.c */
6182 
dkCyan(void)6183 static void dkCyan (void)
6184 {
6185 	SelectColor(0, 203, 196);
6186 }
6187 
dkBlue(void)6188 static void dkBlue (void)
6189 {
6190 	SelectColor(0, 0, 196);
6191 }
6192 
dkGreen(void)6193 static void dkGreen (void)
6194 {
6195 	SelectColor(0, 203, 0);
6196 }
6197 
SetIntColor(int color)6198 static void SetIntColor (int color)
6199 {
6200 	switch (color) {
6201 		case BLACK: Black(); break;
6202 		case RED: Red(); break;
6203 		case GREEN: Green(); break;
6204 		case BLUE: Blue(); break;
6205 		case CYAN: Cyan(); break;
6206 		case MAGENTA: Magenta(); break;
6207 		case YELLOW: Yellow(); break;
6208 		case WHITE: White(); break;
6209 		case GRAY: Gray(); break;
6210 		case LTGRAY: LtGray(); break;
6211 		case DKCYAN: dkCyan(); break;
6212 		case DKBLUE: dkBlue(); break;
6213 		case DKGREEN: dkGreen(); break;
6214 	}
6215 }
6216 
Frame2Rect(RecT PNTR a,int color1,int color2)6217 static void Frame2Rect (RecT PNTR a, int color1, int color2)
6218 {
6219 	MoveTo(a->left, a->top);
6220 	SetIntColor(color1);
6221 	LineTo(a->right, a->top);
6222 	LineTo(a->right, a->bottom);
6223 	SetIntColor(color2);
6224 	LineTo(a->left, a->bottom);
6225 	LineTo(a->left, a->top);
6226 }
6227 
Frame3d(RecT PNTR a)6228 static void Frame3d (RecT PNTR a)
6229 {
6230 	int i, in = 3;
6231 
6232 	SetIntColor(LTGRAY);
6233 	PaintRect(a);
6234 	for (i=0; i < in; i++) {
6235 		if (i > 0) {
6236 			InsetRect(a, 1, 1);
6237 		}
6238 		Frame2Rect(a, WHITE, GRAY);
6239 	}
6240 	for (i=0; i < in; i++) {
6241 		InsetRect(a, 1, 1);
6242 	}
6243 	for (i=0; i < in; i++) {
6244 		InsetRect(a, 1, 1);
6245 		Frame2Rect(a, GRAY, WHITE);
6246 	}
6247 	SelectColor(0, 203, 196);
6248 	PaintRect(a);
6249 }
6250 
DrawColorLine(int x0,int y0,int x1,int y1,int color)6251 static void DrawColorLine (int x0, int y0, int x1, int y1, int color)
6252 {
6253 	SetIntColor(color);
6254 	MoveTo(x0, y0);
6255 	LineTo(x1, y1);
6256 }
6257 
Rect3d(RecT PNTR a,int color)6258 static void Rect3d (RecT PNTR a, int color)
6259 {
6260 	Frame2Rect(a, GRAY, WHITE);
6261 	InsetRect(a, 1, 1);
6262 	Frame2Rect(a, GRAY, WHITE);
6263 	InsetRect(a, 1, 1);
6264 	if (color != -1) {
6265 		SetIntColor(color);
6266 		PaintRect(a);
6267 	}
6268 }
6269 
6270 
6271 
OrfQuitProc(ButtoN b)6272 static void OrfQuitProc (ButtoN b)
6273 
6274 {
6275   QuitProgram ();
6276 }
6277 
CloseProc(ButtoN b)6278 static void CloseProc (ButtoN b)
6279 {
6280 	WindoW   w;
6281 
6282     w = ParentWindow (b);
6283     Remove (w);
6284 }
6285 
draw_rect(SeqPortPtr spp,Int2 ir,RecT PNTR frect,CharPtr vals,CharPtr codes,Boolean paint,OrfViewFormPtr ovp,Int2 strand)6286 static void draw_rect(SeqPortPtr spp, Int2 ir, RecT PNTR frect, CharPtr vals, CharPtr codes, Boolean paint, OrfViewFormPtr ovp, Int2 strand)
6287 {
6288 	Int4 pos;
6289 	Uint1 codon[3], aa;
6290 	Int4 len;
6291 	double x;
6292 	RecT r;
6293 
6294     	SeqPortSeek(spp, ir, SEEK_SET);
6295 		frect->bottom = frect->top + 15;
6296 		len = spp->totlen;
6297 		if (paint) {
6298 			dkGreen();
6299 		} else {
6300 			dkCyan();
6301 		}
6302 		dkCyan();
6303 		PaintRect(frect);
6304 		Black();
6305 		FrameRect(frect);
6306 		for (pos=0; pos < len-2; pos += 3) {
6307 			codon[0] = SeqPortGetResidue(spp);
6308 			codon[1] = SeqPortGetResidue(spp);
6309 			codon[2] = SeqPortGetResidue(spp);
6310 			aa = AAForCodon(codon, codes);
6311 			if (aa == '*') {
6312 				if (strand == Seq_strand_plus) {
6313 					x = frect->left + (pos+ir)*ovp->dx;
6314 				} else {
6315 					x = frect->left + (len+2-(pos+ir))*ovp->dx;
6316 				}
6317 				DrawColorLine(x, frect->top+1, x, frect->bottom-1, RED);
6318 				DrawColorLine(x+1, frect->top+1, x+1, frect->bottom-1, RED);
6319 			}
6320 			if (ovp->alt_start == TRUE) {
6321 				aa = AAForCodon(codon, vals);
6322 			}
6323 			if (aa == 'M') {
6324 				if (strand == Seq_strand_plus) {
6325 					x = frect->left + (pos+ir)*ovp->dx;
6326 				} else {
6327 					x = frect->left + (len+2-(pos+ir))*ovp->dx;
6328 				}
6329 				DrawColorLine(x, frect->top+1, x, frect->bottom-1, WHITE);
6330 				DrawColorLine(x+1, frect->top+1, x+1, frect->bottom-1, WHITE);
6331 			}
6332 		}
6333 		if (paint) {
6334 			r.top = frect->top + 1;
6335 			r.bottom = frect->bottom - 1;
6336 			r.left = frect->left + ovp->from*ovp->dx + 2;
6337 			r.right = frect->left + ovp->to*ovp->dx - 2;
6338 			Magenta();
6339 			PaintRect(&r);
6340 		}
6341 		frect->top = frect->bottom + 4;
6342 }
6343 
draw_frame(Int2 ir,RecT PNTR frect,Boolean paint,OrfViewFormPtr ovp,Int2 strand)6344 static void draw_frame(Int2 ir, RecT PNTR frect, Boolean paint, OrfViewFormPtr ovp, Int2 strand)
6345 {
6346 	RecT r;  /* for ORF */
6347 	ValNodePtr vnp;
6348 	SeqLocPtr slp;
6349 	SeqIntPtr sip;
6350 
6351 	frect->bottom = frect->top + 15;
6352 	LtGray();
6353 	PaintRect(frect);
6354 	Black();
6355 	FrameRect(frect);
6356 	for (vnp = ovp->orfs; vnp; vnp=vnp->next) {
6357 		if (vnp->choice == ir) {
6358 			slp = vnp->data.ptrvalue;
6359 			if (slp == NULL) {
6360 				continue;
6361 			}
6362 			sip = slp->data.ptrvalue;
6363 			if (sip == NULL) {
6364 				continue;
6365 			}
6366 			if (sip->strand == strand) {
6367 				r.top = frect->top + 1;
6368 				r.bottom = frect->bottom - 1;
6369 				r.left = frect->left + sip->from*ovp->dx;
6370 				r.right = frect->left + sip->to*ovp->dx;
6371 				dkCyan();
6372 				PaintRect(&r);
6373 				Black();
6374 				r.top = frect->top;
6375 				r.bottom = frect->bottom;
6376 				FrameRect(&r);
6377 			}
6378 			if (paint) {
6379 				r.top = frect->top + 1;
6380 				r.bottom = frect->bottom - 1;
6381 				r.left = frect->left + ovp->from*ovp->dx + 2;
6382 				r.right = frect->left + ovp->to*ovp->dx - 2;
6383 				Magenta();
6384 				PaintRect(&r);
6385 			}
6386 		}
6387 	}
6388 	frect->top = frect->bottom + 4;
6389 	return;
6390 }
6391 
draw_strands(OrfViewFormPtr ovp)6392 static void draw_strands(OrfViewFormPtr ovp)
6393 {
6394 	Int2 ir, gcode;
6395 	RecT frect;
6396 	SeqPortPtr spp;
6397 	GeneticCodePtr gcp;
6398 	CharPtr vals, codes;
6399 	ValNodePtr vnp;
6400 	Boolean paint;
6401 	RecT PNTR r;
6402 
6403 	r = &(ovp->mi);
6404 	gcode = ovp->gcode;
6405 	gcp = GeneticCodeFind(gcode, NULL);   /* use universal */
6406 	vals = NULL;
6407 	codes = NULL;
6408 	for (vnp = (ValNodePtr)gcp->data.ptrvalue; vnp != NULL; vnp = vnp->next)
6409 	{
6410 		if (vnp->choice == 6)   /* sncbieaa */
6411 			vals = (CharPtr)vnp->data.ptrvalue;
6412 		else if (vnp->choice == 3)  /* ncbieaa */
6413 			codes = (CharPtr)vnp->data.ptrvalue;
6414 	}
6415 	if (vals == NULL) {
6416 		vals = codes;
6417 	}
6418 	frect.left = r->left + 11;
6419 	frect.right = r->right - 11;
6420 	frect.top = r->top + 4;
6421 	ovp->dx = (frect.right - frect.left - 1.) / (ovp->bsp)->length;
6422 	ovp->dy = (r->bottom - r->top - 1.) / 6.;
6423 	spp = SeqPortNew(ovp->bsp, 0, -1, Seq_strand_plus, Seq_code_ncbi4na);
6424 	for (ir=0; ir < 3; ir++) {
6425 		if (ovp->from == 0 && ovp->to == 0) {
6426 			paint = FALSE;
6427 		} else if (ovp->strand == Seq_strand_plus && ovp->frame == ir) {
6428 			paint = TRUE;
6429 		} else {
6430 			paint = FALSE;
6431 		}
6432 		if (ovp->orf_only) {
6433 			draw_frame(ir, &frect, paint, ovp, Seq_strand_plus);
6434 		} else {
6435 			draw_rect(spp, ir, &frect, vals, codes, paint, ovp, Seq_strand_plus);
6436 		}
6437 	}
6438 	SeqPortFree(spp);
6439 	spp = SeqPortNew(ovp->bsp, 0, -1, Seq_strand_minus, Seq_code_ncbi4na);
6440 	frect.top += 7;
6441 	for (ir=0; ir < 3; ir++) {
6442 		if (ovp->from == 0 && ovp->to == 0) {
6443 			paint = FALSE;
6444 		} else if (ovp->strand == Seq_strand_minus && ovp->frame == ir) {
6445 			paint = TRUE;
6446 		} else {
6447 			paint = FALSE;
6448 		}
6449 		if (ovp->orf_only) {
6450 			draw_frame(ir, &frect, paint, ovp, Seq_strand_minus);
6451 		} else {
6452 			draw_rect(spp, ir, &frect, vals, codes, paint, ovp, Seq_strand_minus);
6453 		}
6454 	}
6455 
6456 	SeqPortFree(spp);
6457 }
6458 
DrawIcon(IcoN ic0)6459 static void DrawIcon(IcoN ic0)
6460 {
6461 	RecT r;
6462 	OrfViewFormPtr ovp;
6463 
6464 	ovp = (OrfViewFormPtr) GetObjectExtra (ic0);
6465 	ObjectRect(ovp->icon, &r);
6466 	ovp->mi.left = mi0.left + r.left;
6467 	ovp->mi.right = mi0.right + r.left;
6468 	ovp->mi.top = mi0.top + r.top;
6469 	ovp->mi.bottom = mi0.bottom + r.top;
6470 	Frame3d(&r);
6471 	Rect3d(&(ovp->mi), LTGRAY);
6472 	draw_strands(ovp);
6473 }
6474 
notify(DoC d,Int2 item,Int2 raw,Int2 col,Boolean event)6475 static void notify( DoC d, Int2 item, Int2 raw, Int2 col, Boolean event)
6476 {
6477 	ValNodePtr vnp;
6478 	SeqLocPtr slp, slptmp;
6479 	SeqIntPtr sip;
6480 	Int2 i;
6481 	Int2	itemOld1;
6482 	Int2	itemOld2;
6483 	Boolean status;
6484 	OrfViewFormPtr ovp;
6485 	Int2 top, bottom;
6486 	BaR sb;
6487 	Int2 startsAt;
6488 
6489 	if( item == 0) {
6490 		return;
6491 	}
6492 	ovp = (OrfViewFormPtr) GetObjectExtra (d);
6493 	for (vnp = ovp->orfs, i = 1; i < item && vnp; i++, vnp=vnp->next) continue;
6494 	if (vnp == NULL) {
6495 		return;
6496 	}
6497 	if (ItemIsVisible (d, item, &top, &bottom, NULL) == FALSE) {
6498       GetItemParams (d, item, &startsAt, NULL, NULL, NULL, NULL);
6499       sb = GetSlateVScrollBar ((SlatE) d);
6500       CorrectBarValue (sb, startsAt);
6501 	}
6502     GetDocHighlight(d, &itemOld1, &itemOld2);
6503 	SetDocHighlight(d, item, item);
6504 	UpdateDocument(d, itemOld1, itemOld2);
6505 	UpdateDocument(d, item, item);
6506 
6507 	ovp->frame = vnp->choice;
6508 	slp = vnp->data.ptrvalue;
6509 	sip = slp->data.ptrvalue;
6510 	ovp->strand = sip->strand;
6511 	ovp->from = sip->from;
6512 	ovp->to = sip->to;
6513 	DrawIcon(ovp->icon);
6514 	status = GetStatus(ovp->icon);
6515 	SetStatus(ovp->icon, !status);
6516 
6517     if (! ovp->standAlone) {
6518 		slptmp = AsnIoMemCopy(slp, (AsnReadFunc) SeqLocAsnRead,
6519 				(AsnWriteFunc) SeqLocAsnWrite);
6520 		ovp->select_orf = slptmp;
6521 		ObjMgrSelect (ovp->bsp_entityID, ovp->bsp_itemID, OBJ_BIOSEQ,
6522 				OM_REGION_SEQLOC, slptmp);
6523 	}
6524 
6525 	Update();
6526 }
6527 
LaunchOrfFindCDSEditor(OrfViewFormPtr ovp)6528 static void LaunchOrfFindCDSEditor (OrfViewFormPtr ovp)
6529 {
6530 	OMProcControl  ompc;
6531 	ObjMgrProcPtr  ompp;
6532 	ObjMgrPtr      omp;
6533     Int2           retval;
6534 
6535     if (ovp == NULL)
6536     {
6537     	return;
6538     }
6539     omp = ObjMgrGet ();
6540     if (omp == NULL)
6541     {
6542     	return;
6543     }
6544     ompp = NULL;
6545     while ((ompp = ObjMgrProcFindNext (omp, OMPROC_EDIT,
6546 				          OBJ_SEQFEAT, 0, ompp)) != NULL)
6547 
6548 	{
6549         if (ompp->subinputtype == FEATDEF_CDS)
6550         {
6551         	break;
6552         }
6553 	}
6554 	if (ompp == NULL) return;
6555 	MemSet ((Pointer) (&ompc), 0, sizeof (OMProcControl));
6556     ompc.input_entityID = ovp->bsp_entityID;
6557     ompc.input_itemID = ovp->bsp_itemID;
6558     ompc.input_itemtype = OBJ_BIOSEQ;
6559     GatherDataForProc (&ompc, FALSE);
6560     ompc.proc = ompp;
6561     retval = (*(ompp->func)) (&ompc);
6562     if (retval == OM_MSG_RET_ERROR)
6563     {
6564         ErrShow ();
6565     }
6566 }
6567 
myprocessmousepos(IcoN ic,PoinT pt,Boolean edit_on_dblclick)6568 static void myprocessmousepos (IcoN ic, PoinT pt, Boolean edit_on_dblclick)
6569 {
6570 	RecT r;
6571 	Int2 ir;
6572 	Int4 pos;
6573 	ValNodePtr vnp;
6574 	SeqLocPtr slp;
6575 	SeqIntPtr sip;
6576 	Boolean status;
6577 	OrfViewFormPtr ovp;
6578 	Int2	item;
6579 	Int2 top, bottom;
6580 	BaR sb;
6581 	Int2 startsAt;
6582 	DoC doc;
6583 
6584 	if (edit_on_dblclick && ! Nlm_dblClick)
6585 	{
6586 	  return;
6587 	}
6588 
6589 	ovp = GetObjectExtra((IcoN) ic);
6590 	ObjectRect(ic, &r);
6591 	if (!PtInRect(pt, &(ovp->mi))) {
6592 		return;
6593 	}
6594 	doc = ovp->doc;
6595 	r.left = ovp->mi.left + 11;
6596 	r.right = ovp->mi.right - 11;
6597 	r.top = ovp->mi.top + 4;
6598 	ovp->dx = (r.right - r.left - 1.) / (ovp->bsp)->length;
6599 	ovp->dy = (ovp->mi.bottom - ovp->mi.top - 1.) / 6.;
6600 	for (ir=0; ir < 3; ir++) {
6601 		r.bottom = r.top + 15;
6602 		if (pt.y < r.bottom && pt.y > r.top) {
6603 			break;
6604 		}
6605 		r.top = r.bottom + 4;
6606 	}
6607 	if (ir < 3) {
6608 		pos = (pt.x - r.left)/ovp->dx - ir;
6609 		for (vnp=ovp->orfs, item=1; vnp; vnp=vnp->next, item++) {
6610 			slp = vnp->data.ptrvalue;
6611 			if (slp == NULL) continue;
6612 			sip = slp->data.ptrvalue;
6613 			if (sip == NULL) continue;
6614 			if (vnp->choice != ir || sip->strand != Seq_strand_plus) {
6615 				continue;
6616 			}
6617 			if (pos < sip->to && pos > sip->from) {
6618 				break;
6619 			}
6620 		}
6621 		if (vnp == NULL) {
6622 			Beep();
6623 			return;
6624 		}
6625 		if (slp == NULL) return;
6626 		if (sip == NULL) return;
6627 		ovp->frame = ir;
6628 		ovp->strand = sip->strand;
6629 		ovp->from = sip->from;
6630 		ovp->to = sip->to;
6631 		ovp->select_orf = AsnIoMemCopy(slp, (AsnReadFunc) SeqLocAsnRead,
6632 		(AsnWriteFunc) SeqLocAsnWrite);
6633 		status = GetStatus(ic);
6634 		SetStatus(ic, !status);
6635 		Update();
6636 		Select(doc);
6637 		SetDocHighlight(doc, item, item);
6638 		if (ItemIsVisible (doc, item, &top, &bottom, NULL) == FALSE) {
6639       	GetItemParams (doc, item, &startsAt, NULL, NULL, NULL, NULL);
6640       	sb = GetSlateVScrollBar ((SlatE) doc);
6641       	CorrectBarValue (sb, startsAt);
6642 		}
6643 		UpdateDocument(doc, 0, 0);
6644 
6645 		if (! ovp->standAlone) {
6646 			if (ovp->select_orf != NULL) {
6647 				ObjMgrSelect (ovp->bsp_entityID, ovp->bsp_itemID, OBJ_BIOSEQ,
6648 					OM_REGION_SEQLOC, ovp->select_orf);
6649 				if (edit_on_dblclick)
6650 		        {
6651 		            /* launch CDS Editor */
6652                     LaunchOrfFindCDSEditor (ovp);
6653 		        }
6654 			}
6655 		}
6656 		Update();
6657 		return;
6658 	}
6659 	r.top += 7;
6660 	for (ir=0; ir < 3; ir++) {
6661 		r.bottom = r.top + 15;
6662 		if (pt.y < r.bottom && pt.y > r.top) {
6663 			break;
6664 		}
6665 		r.top = r.bottom + 4;
6666 	}
6667 	if (ir < 3) {
6668 		pos = (pt.x - r.left)/ovp->dx - ir;
6669 		for (vnp=ovp->orfs, item=1; vnp; vnp=vnp->next, item++) {
6670 			slp = vnp->data.ptrvalue;
6671 			if (slp == NULL) continue;
6672 			sip = slp->data.ptrvalue;
6673 			if (sip == NULL) continue;
6674 			if (vnp->choice != ir  || sip->strand != Seq_strand_minus) {
6675 				continue;
6676 			}
6677 			if (pos < sip->to && pos > sip->from) {
6678 				break;
6679 			}
6680 		}
6681 		if (vnp == NULL) {
6682 			Beep();
6683 			return;
6684 		}
6685 		if (slp == NULL) return;
6686 		if (sip == NULL) return;
6687 		ovp->frame = ir;
6688 		ovp->strand = sip->strand;
6689 		ovp->from = sip->from;
6690 		ovp->to = sip->to;
6691 		ovp->select_orf = AsnIoMemCopy(slp, (AsnReadFunc) SeqLocAsnRead,
6692 					(AsnWriteFunc) SeqLocAsnWrite);
6693 		status = GetStatus(ic);
6694 		SetStatus(ic, !status);
6695 		Update();
6696 		Select(doc);
6697 		SetDocHighlight(doc, item, item);
6698 		if (ItemIsVisible (doc, item, &top, &bottom, NULL) == FALSE) {
6699       	GetItemParams (doc, item, &startsAt, NULL, NULL, NULL, NULL);
6700       	sb = GetSlateVScrollBar ((SlatE) doc);
6701       	CorrectBarValue (sb, startsAt);
6702 		}
6703 		UpdateDocument(doc, 0, 0);
6704 	}
6705 	if (! ovp->standAlone) {
6706 		if (ovp->select_orf != NULL) {
6707 			ObjMgrSelect (ovp->bsp_entityID, ovp->bsp_itemID, OBJ_BIOSEQ,
6708 				OM_REGION_SEQLOC, ovp->select_orf);
6709 			if (edit_on_dblclick)
6710 		    {
6711 		        /* launch CDS Editor */
6712                 LaunchOrfFindCDSEditor (ovp);
6713 		    }
6714 		}
6715 	}
6716 
6717 	Update();
6718 	return;
6719 }
6720 
myrelease(IcoN ic,PoinT pt)6721 static void myrelease(IcoN ic, PoinT pt)
6722 {
6723     myprocessmousepos (ic, pt, FALSE);
6724 }
6725 
myclick(IcoN ic,PoinT pt)6726 static void myclick(IcoN ic, PoinT pt)
6727 {
6728     myprocessmousepos (ic, pt, TRUE);
6729 }
6730 
6731 
6732 /* show all ORF from List without starts and stops */
ORFProc(ButtoN b)6733 static void ORFProc(ButtoN b)
6734 {
6735 	OrfViewFormPtr ovp;
6736 	Boolean status;
6737 
6738 	if ((ovp = (OrfViewFormPtr) GetObjectExtra (b)) == NULL) {
6739 		return;
6740 	}
6741 	ovp->orf_only = !ovp->orf_only;
6742 	draw_strands(ovp);
6743 	status = GetStatus(ovp->icon);
6744 	SetStatus(ovp->icon, !status);
6745 	Update();
6746 }
AddOrfListToDoc(DoC doc,ValNodePtr list)6747 static void AddOrfListToDoc(DoC doc, ValNodePtr list)
6748 {
6749 	ParPtr	par;
6750 	ValNodePtr vnp;
6751 	SeqLocPtr slp, tmp;
6752 	SeqIntPtr sip;
6753 	Boolean minus;
6754 	Int2 l, i;
6755 	CharPtr buf, str;
6756 	OrfViewFormPtr ovp;
6757 
6758 	Reset(doc);
6759 	ovp = (OrfViewFormPtr) GetObjectExtra(doc);
6760 	par = (ParPtr) MemNew(sizeof (ParData));
6761   	par->openSpace = FALSE;
6762   	par->keepWithNext = 1;
6763   	par->keepTogether = 1;
6764 	par->newPage  = 1;
6765   	par->tabStops     = 1;
6766 	for (vnp = list, i=0; vnp; vnp=vnp->next, i++) {
6767 		minus = FALSE;
6768 		tmp = (SeqLocPtr) vnp->data.ptrvalue;
6769 		slp = AsnIoMemCopy ((Pointer) tmp, (AsnReadFunc) SeqLocAsnRead,
6770                                         (AsnWriteFunc) SeqLocAsnWrite);
6771 		if (slp == NULL) {
6772 			continue;
6773 		}
6774         slp->next = NULL;
6775 		sip = (SeqIntPtr) slp->data.ptrvalue;
6776 		if (sip->strand == Seq_strand_minus) {
6777 			sip->strand = Seq_strand_plus;
6778 			minus = TRUE;
6779 		}
6780 		str = FlatLoc(ovp->bsp, slp);
6781 		MemFree(slp);
6782 		l = StringLen(str);
6783 		if (minus == TRUE) {
6784 			buf = MemNew(l+4);
6785 			sprintf(buf, "c(%s)", str);
6786 			AppendText(doc, buf, par, NULL, NULL);
6787 			MemFree(buf);
6788 			sip->strand = Seq_strand_minus;
6789 		} else {
6790 			AppendText(doc, str, par, NULL, NULL);
6791 		}
6792 	}
6793 	UpdateDocument(doc, 0, 0);
6794 }
6795 
ValNodeSeqLocListFree(ValNodePtr vnp)6796 static ValNodePtr ValNodeSeqLocListFree (ValNodePtr vnp)
6797 {
6798   if (vnp != NULL) {
6799     vnp->next = ValNodeSeqLocListFree(vnp->next);
6800     vnp->data.ptrvalue = SeqLocFree (vnp->data.ptrvalue);
6801     vnp = ValNodeFree (vnp);
6802   }
6803   return vnp;
6804 }
6805 
6806 static void PopulateOrfList (OrfViewFormPtr ovp);
6807 static ValNodePtr ListOrfs (BioseqPtr bsp, Boolean altstart, Int4 min_len, Boolean allow_partial);
6808 static void SortOrfs (OrfViewFormPtr ovp);
6809 
AltProc(GrouP g)6810 static void AltProc(GrouP g)
6811 {
6812 	OrfViewFormPtr ovp;
6813 	Boolean status;
6814 
6815 	if ((ovp = (OrfViewFormPtr) GetObjectExtra (g)) == NULL) {
6816 		return;
6817 	}
6818 
6819 	ovp->orfs = ValNodeSeqLocListFree(ovp->orfs);
6820 	if (GetValue (ovp->start_choice) == 1) {
6821 	  ovp->alt_start = FALSE;
6822 	} else {
6823 	  ovp->alt_start = TRUE;
6824 	}
6825 	ovp->orfs =  ListOrfs(ovp->bsp, ovp->alt_start, ovp->len, ovp->allow_partial);
6826 	SortOrfs(ovp);
6827 	PopulateOrfList (ovp);
6828 /*	AddOrfListToDoc(ovp->doc, ovp->orfs); */
6829 	ovp->from = 0;
6830 	ovp->to = 0;
6831 	draw_strands(ovp);
6832 	status = GetStatus(ovp->icon);
6833 	SetStatus(ovp->icon, !status);
6834 	Update();
6835 }
6836 
ChangeAAcutoff(PopuP p)6837 static void ChangeAAcutoff(PopuP p)
6838 {
6839 	OrfViewFormPtr ovp;
6840 	Int2 i;
6841 	Boolean status;
6842 
6843 	ovp = (OrfViewFormPtr) GetObjectExtra(p);
6844 	i = GetValue((PopuP) p);
6845 	switch (i) {
6846 		case 1:
6847 			ovp->len = 10;
6848 			break;
6849 		case 2:
6850 			ovp->len = 50;
6851 			break;
6852 		case 3:
6853 			ovp->len = 100;
6854 			break;
6855 		default:
6856 			ovp->len = 3;
6857 			break;
6858 	}
6859   ovp->orfs = ValNodeSeqLocListFree(ovp->orfs);
6860 	ovp->orfs =  ListOrfs(ovp->bsp, ovp->alt_start, ovp->len, ovp->allow_partial);
6861 	SortOrfs(ovp);
6862 	PopulateOrfList (ovp);
6863 
6864 	draw_strands(ovp);
6865 	status = GetStatus(ovp->icon);
6866 	SetStatus(ovp->icon, !status);
6867 	Update();
6868 }
6869 
ShowPartialOrfs(ButtoN b)6870 static void ShowPartialOrfs (ButtoN b)
6871 {
6872 	OrfViewFormPtr ovp;
6873 
6874 	ovp = (OrfViewFormPtr) GetObjectExtra(b);
6875 
6876   if (ovp == NULL)
6877   {
6878     return;
6879   }
6880 
6881   ovp->allow_partial = GetStatus (ovp->show_partial_btn);
6882 
6883   ovp->orfs = ValNodeSeqLocListFree(ovp->orfs);
6884 	ovp->orfs =  ListOrfs(ovp->bsp, ovp->alt_start, ovp->len, ovp->allow_partial);
6885 	SortOrfs(ovp);
6886 	PopulateOrfList (ovp);
6887 
6888 	draw_strands(ovp);
6889 
6890 	Update();
6891 }
6892 
6893 
OrfViewerMsgFunc(OMMsgStructPtr ommsp)6894 static Int2 LIBCALLBACK OrfViewerMsgFunc (OMMsgStructPtr ommsp)
6895 
6896 {
6897   ObjMgrDataPtr   omdp;
6898   OMUserDataPtr   omudp;
6899   OrfViewFormPtr  ovp;
6900 
6901   omudp = (OMUserDataPtr)(ommsp->omuserdata);
6902   if (omudp == NULL) return OM_MSG_RET_ERROR;
6903   ovp = (OrfViewFormPtr) omudp->userdata.ptrvalue;
6904   if (ovp == NULL) return OM_MSG_RET_ERROR;
6905   switch (ommsp->message) {
6906     case OM_MSG_DEL:
6907       omdp = ObjMgrGetData (ommsp->entityID);
6908       if (omdp != NULL) {
6909         if (ObjMgrWholeEntity (omdp, ommsp->itemID, ommsp->itemtype)) {
6910           if (ovp != NULL) {
6911             Remove (ovp->form);
6912           }
6913           return OM_MSG_RET_OK;
6914         }
6915       }
6916       break;
6917     default :
6918       break;
6919   }
6920   return OM_MSG_RET_OK;
6921 }
6922 
CleanupOrfViewer(GraphiC g,VoidPtr data)6923 static void CleanupOrfViewer (GraphiC g, VoidPtr data)
6924 
6925 {
6926   OrfViewFormPtr  ovp;
6927 
6928   ovp = (OrfViewFormPtr) data;
6929   if (ovp != NULL && ovp->input_entityID > 0 && ovp->procid > 0) {
6930     ObjMgrFreeUserData (ovp->input_entityID, ovp->procid, ovp->proctype, ovp->userkey);
6931   }
6932   StdCleanupFormProc (g, data);
6933 }
6934 
PopulateOrfList(OrfViewFormPtr ovp)6935 static void PopulateOrfList (OrfViewFormPtr ovp)
6936 {
6937 	ValNodePtr     vnp;
6938 	Int4           i, l, select_pos = 0;
6939 	Boolean        minus;
6940 	SeqLocPtr      tmp, slp;
6941 	SeqIntPtr      sip;
6942 	CharPtr        str, buf;
6943 
6944     if (ovp == NULL) {
6945       return;
6946     }
6947 
6948     Reset (ovp->doc);
6949 	for (vnp = ovp->orfs, i=0; vnp; vnp=vnp->next, i++) {
6950 		minus = FALSE;
6951 		tmp = (SeqLocPtr) vnp->data.ptrvalue;
6952 		if (ovp->select_orf != NULL && SeqLocCompare (ovp->select_orf, tmp) == SLC_A_EQ_B) {
6953 		  select_pos = i + 1;
6954 		}
6955 		slp = AsnIoMemCopy ((Pointer) tmp, (AsnReadFunc) SeqLocAsnRead,
6956                                         (AsnWriteFunc) SeqLocAsnWrite);
6957         if (slp == NULL) {
6958         	continue;
6959         }
6960         slp->next = NULL;
6961 		sip = (SeqIntPtr) slp->data.ptrvalue;
6962 		if (sip->strand == Seq_strand_minus) {
6963 			sip->strand = Seq_strand_plus;
6964 			minus = TRUE;
6965 		}
6966 		str = FlatLoc(ovp->bsp, slp);
6967 		MemFree(slp);
6968 		l = StringLen(str);
6969 		if (minus == TRUE) {
6970 			buf = MemNew(l+4);
6971 			sprintf(buf, "c(%s)", str);
6972 			AppendText(ovp->doc, buf, &(ovp->par), NULL, NULL);
6973 			MemFree(buf);
6974 			sip->strand = Seq_strand_minus;
6975 		} else {
6976 			AppendText(ovp->doc, str, &(ovp->par), NULL, NULL);
6977 		}
6978 	}
6979 	notify (ovp->doc, select_pos, 0, 0, FALSE);
6980 	UpdateDocument (ovp->doc, 0, 0);
6981 }
6982 
SortOrfsByStart(VoidPtr vp1,VoidPtr vp2)6983 static int LIBCALLBACK SortOrfsByStart (VoidPtr vp1, VoidPtr vp2)
6984 {
6985 	ValNodePtr vnp1, vnp2;
6986 	ValNodePtr PNTR vnpp1;
6987 	ValNodePtr PNTR vnpp2;
6988 	Int4 l1, l2;
6989 
6990 	vnpp1 = (ValNodePtr PNTR) vp1;
6991 	vnpp2 = (ValNodePtr PNTR) vp2;
6992 	vnp1 = *vnpp1;
6993 	vnp2 = *vnpp2;
6994 
6995 	if (vnp1->data.ptrvalue == NULL) {
6996 	  l1 = 2;
6997 	} else if (vnp2->data.ptrvalue == NULL) {
6998 	  l2 = 2;
6999 	}
7000 	l1 = SeqLocStart((SeqLocPtr) vnp1->data.ptrvalue);
7001 	l2 = SeqLocStart((SeqLocPtr) vnp2->data.ptrvalue);
7002 
7003 	if (l1 < l2)
7004 		return -1;
7005 	else if (l1 > l2)
7006 		return 1;
7007 	else
7008 		return 0;
7009 }
7010 
SortOrfsByLength(VoidPtr vp1,VoidPtr vp2)7011 static int LIBCALLBACK SortOrfsByLength (VoidPtr vp1, VoidPtr vp2)
7012 {
7013 	ValNodePtr vnp1, vnp2;
7014 	ValNodePtr PNTR vnpp1;
7015 	ValNodePtr PNTR vnpp2;
7016 	Int4 l1, l2;
7017 
7018 	vnpp1 = (ValNodePtr PNTR) vp1;
7019 	vnpp2 = (ValNodePtr PNTR) vp2;
7020 	vnp1 = *vnpp1;
7021 	vnp2 = *vnpp2;
7022 	l1 = SeqLocLen((SeqLocPtr) vnp1->data.ptrvalue);
7023 	l2 = SeqLocLen((SeqLocPtr) vnp2->data.ptrvalue);
7024 
7025 	if (l1 > l2)
7026 		return -1;
7027 	else if (l1 < l2)
7028 		return 1;
7029 	else
7030 		return 0;
7031 }
7032 
7033 
SortOrfs(OrfViewFormPtr ovp)7034 static void SortOrfs (OrfViewFormPtr ovp)
7035 {
7036   Int4           sort_choice;
7037 
7038   if (ovp == NULL) return;
7039 
7040   sort_choice = GetValue (ovp->orf_order);
7041   if (sort_choice == 1) {
7042     VnpHeapSort(&(ovp->orfs), SortOrfsByLength);
7043   } else {
7044     VnpHeapSort(&(ovp->orfs), SortOrfsByStart);
7045   }
7046 }
7047 
ReorderOrfs(GrouP g)7048 static void ReorderOrfs (GrouP g)
7049 {
7050   OrfViewFormPtr ovp;
7051 
7052   ovp = (OrfViewFormPtr) GetObjectExtra (g);
7053   if (ovp == NULL) return;
7054   SortOrfs (ovp);
7055   PopulateOrfList (ovp);
7056 }
7057 
7058 typedef struct orfdata {
7059   Int4       curlen [6], currstart [6], sublen [6];
7060   ValNodePtr lastvnp[6];
7061   Boolean    inorf [6], altstart;
7062   Int4       min_len;
7063   Int4       bioseq_len;
7064   ValNodePtr orf_list;
7065   SeqIdPtr   sip;
7066   Boolean    allow_partial_orf;
7067   Boolean    partial_other_end[6];
7068 } OrfData, PNTR OrfDataPtr;
7069 
7070 
TreatLikeStop(Int2 frame,Int4 pos,Uint1 strand,Int4 len)7071 static Boolean TreatLikeStop (Int2 frame, Int4 pos, Uint1 strand, Int4 len)
7072 {
7073   Int4 remainder = len % 3;
7074   Boolean like_stop = FALSE;
7075 
7076   if (strand == Seq_strand_minus) {
7077     if (pos < 3) {
7078       like_stop = TRUE;
7079     }
7080   } else {
7081     if (pos >= len - remainder - 3) {
7082       like_stop = TRUE;
7083     }
7084   }
7085   return like_stop;
7086 }
7087 
7088 
LookForOrfs(Int4 position,Char residue,Boolean atgStart,Boolean altStart,Boolean orfStop,Int2 frame,Uint1 strand,Pointer userdata)7089 static void LIBCALLBACK LookForOrfs (
7090   Int4 position,
7091   Char residue,
7092   Boolean atgStart,
7093   Boolean altStart,
7094   Boolean orfStop,
7095   Int2 frame,
7096   Uint1 strand,
7097   Pointer userdata
7098 )
7099 
7100 {
7101   Int2        idx;
7102   OrfDataPtr  odp;
7103   SeqLocPtr   slp, tmp;
7104   Boolean     start_of_seq = FALSE;
7105   Boolean     partial_this_end = FALSE;
7106 
7107   odp = (OrfDataPtr) userdata;
7108 
7109   if (strand == Seq_strand_plus) {
7110 
7111     /* top strand */
7112 
7113     idx = frame;
7114     if (position == 0 && (atgStart || (altStart && odp->altstart)))
7115     {
7116       /* not partial at 5' end */
7117       odp->partial_other_end[idx] = FALSE;
7118     }
7119 
7120     if (odp->inorf [idx]) {
7121       if (!orfStop) {
7122         /* treat the end of the sequence like a stop codon */
7123         if (odp->allow_partial_orf && TreatLikeStop(frame, position, strand, odp->bioseq_len)) {
7124           position += 3;
7125           (odp->curlen[idx])++;
7126           orfStop = TRUE;
7127           partial_this_end = TRUE;
7128         }
7129       }
7130       if (orfStop) {
7131         odp->inorf [idx] = FALSE;
7132         if (odp->curlen[idx] >= odp->min_len) {
7133           slp = SeqLocIntNew (odp->currstart [idx] + idx,
7134                               MIN (position + 2, (Int4) odp->bioseq_len - 1),
7135                               strand, odp->sip);
7136           SetSeqLocPartial (slp, odp->partial_other_end[idx], partial_this_end);
7137           ValNodeAddPointer (&(odp->orf_list), frame, slp);
7138         }
7139       } else {
7140         (odp->curlen [idx])++;
7141       }
7142     } else if (atgStart || (altStart && odp->altstart)) {
7143       odp->inorf [idx] = TRUE;
7144       odp->curlen [idx] = 1;
7145       odp->currstart [idx] = position - frame;
7146       odp->partial_other_end [idx] = FALSE;
7147     }
7148   } else {
7149 
7150     /* bottom strand */
7151 
7152     idx = frame + 3;
7153 
7154     if (!orfStop && odp->allow_partial_orf) {
7155       start_of_seq = TreatLikeStop (frame, position, strand, odp->bioseq_len);
7156     }
7157     if (orfStop) {
7158         odp->curlen [idx] = 0;
7159         odp->sublen [idx] = 0;
7160         odp->currstart [idx] = position - frame;
7161         odp->partial_other_end[idx] = FALSE;
7162     } else if (start_of_seq) {
7163         odp->curlen [idx] = 1;
7164         odp->sublen [idx] = 1;
7165         odp->currstart [idx] = position - frame - 3;
7166     } else if (atgStart || (altStart && odp->altstart) || (odp->allow_partial_orf && position >= odp->bioseq_len - 5)) {
7167       (odp->sublen [idx])++;
7168       odp->curlen [idx] = odp->sublen [idx];
7169       if (odp->allow_partial_orf && position >= odp->bioseq_len - 5)
7170       {
7171         /* also include partial codon at partial end */
7172         (odp->curlen[idx]) ++;
7173         if (!atgStart && (!altStart || !odp->altstart))
7174         {
7175           partial_this_end = TRUE;
7176         }
7177       }
7178       if (odp->curlen[idx] >= odp->min_len) {
7179         slp = SeqLocIntNew (MAX ((Int4) odp->currstart [idx] + idx - 3, (Int4) 0),
7180                             MIN (odp->currstart [idx] + idx - 3 + (odp->curlen [idx]) * 3 + 2, odp->bioseq_len - 1),
7181                             Seq_strand_minus, odp->sip);
7182         SetSeqLocPartial (slp, partial_this_end, odp->partial_other_end[idx]);
7183         if (odp->lastvnp[idx] != NULL) {
7184           tmp = (SeqLocPtr) odp->lastvnp[idx]->data.ptrvalue;
7185           if (SeqLocStart (tmp) == SeqLocStart (slp)) {
7186             tmp = SeqLocFree (tmp);
7187             odp->lastvnp[idx]->data.ptrvalue = slp;
7188           } else {
7189             odp->lastvnp[idx] = ValNodeAddPointer (&(odp->orf_list), frame, slp);
7190           }
7191         } else {
7192           odp->lastvnp[idx] = ValNodeAddPointer (&(odp->orf_list), frame, slp);
7193         }
7194       }
7195     } else {
7196       (odp->sublen [idx])++;
7197     }
7198   }
7199 }
7200 
ListOrfs(BioseqPtr bsp,Boolean altstart,Int4 min_len,Boolean allow_partial)7201 static ValNodePtr ListOrfs (
7202   BioseqPtr bsp,
7203   Boolean altstart,
7204   Int4 min_len,
7205   Boolean allow_partial
7206 )
7207 
7208 {
7209   Int2            i;
7210   OrfData         od;
7211   TransTablePtr   tbl;
7212   Int2            genCode;
7213 
7214   if (bsp == NULL) return NULL;
7215 
7216   od.sip = SeqIdFindBest (bsp->id, 0);
7217   genCode = GetGcodeFromBioseq(bsp);
7218 
7219 
7220   for (i = 0; i < 6; i++) {
7221     od.curlen [i] = INT4_MIN;
7222     od.currstart [i] = 0;
7223     od.sublen [i] = INT4_MIN;
7224     od.inorf [i] = FALSE;
7225     od.lastvnp [i] = NULL;
7226     od.partial_other_end [i] = allow_partial;
7227   }
7228 
7229   if (allow_partial) {
7230     /* allow 5' partial ORFs */
7231     for (i = 0; i < 3; i++) {
7232       od.inorf[i] = TRUE;
7233       od.curlen [i] = 1;
7234       od.currstart [i] = 0 - i;
7235     }
7236   }
7237 
7238   od.altstart = altstart;
7239   od.orf_list = NULL;
7240   od.min_len = min_len;
7241   od.bioseq_len = bsp->length;
7242   od.allow_partial_orf = allow_partial;
7243 
7244   /* use simultaneous 6-frame translation finite state machine */
7245 
7246   tbl = PersistentTransTableByGenCode (genCode);
7247   if (tbl != NULL) {
7248     TransTableProcessBioseq (tbl, LookForOrfs, (Pointer) &od, bsp);
7249   }
7250 
7251   return od.orf_list;
7252 }
7253 
LaunchOrfViewer(BioseqPtr bsp,Uint2 entityID,Uint4 itemID,Boolean standAlone)7254 extern void LaunchOrfViewer (BioseqPtr bsp, Uint2 entityID, Uint4 itemID, Boolean standAlone)
7255 {
7256 	ButtoN qu, b1;
7257 	GrouP g, k;
7258 	OrfViewFormPtr ovp;
7259 	WindoW w;
7260 	IcoN ic;
7261 	PopuP pu;
7262 	ObjMgrPtr omp;
7263 	ObjMgrProcPtr ompp;
7264 	OMUserDataPtr omudp;
7265 
7266 	WatchCursor ();
7267 	Update ();
7268 	ovp = (OrfViewFormPtr) MemNew (sizeof (OrfViewForm));
7269 	ovp->bsp = bsp;
7270 	ovp->select_orf = NULL;
7271 	ovp->input_entityID = entityID;
7272 	ovp->bsp_entityID = entityID;
7273 	ovp->bsp_itemID = itemID;
7274 	ovp->len = 10;
7275 	ovp->alt_start = FALSE;
7276   ovp->allow_partial = TRUE;
7277 #if 1
7278     ovp->orfs = ListOrfs (bsp, ovp->alt_start, ovp->len, ovp->allow_partial);
7279 #else
7280 	ovp->orfs =  GetOrfList(bsp, ORF_LENGTH);
7281 #endif
7282 	ovp->orf_only = TRUE;
7283 	ovp->gcode = 1;
7284 	ovp->standAlone = standAlone;
7285 	w = FixedWindow(-50, -33, -10, -10, "Orf Finder", NULL);
7286 	SetObjectExtra (w, ovp, CleanupOrfViewer);
7287 	ovp->form = (ForM) w;
7288   g = HiddenGroup (w, 6, 0, NULL);
7289   SetGroupSpacing (g, 6, 0);
7290 	if (ovp->standAlone) {
7291 		qu = PushButton(g, "Quit", OrfQuitProc);
7292 	} else {
7293 		qu = PushButton(g, "Close", CloseProc);
7294 	}
7295 	b1 = PushButton(g, "ORF", ORFProc);
7296 	SetObjectExtra (b1, ovp, NULL);
7297 	ovp->start_choice = NormalGroup (g, 2, 0, "Initiation Codon", programFont, AltProc);
7298   SetObjectExtra (ovp->start_choice, ovp, NULL);
7299   RadioButton (ovp->start_choice, "Standard");
7300   RadioButton (ovp->start_choice, "Alternative");
7301   SetValue (ovp->start_choice, 1);
7302 	StaticPrompt(g, "ORF length", 0, 16, systemFont, '1');
7303 	pu = PopupList(g, TRUE, ChangeAAcutoff );
7304 	PopupItem(pu, "10");
7305 	PopupItem(pu, "50");
7306 	PopupItem(pu, "100");
7307 	SetValue(pu, 1);
7308 	SetObjectExtra (pu, ovp, NULL);
7309 
7310   ovp->show_partial_btn = CheckBox (g, "Show Partial ORFs", ShowPartialOrfs);
7311   SetObjectExtra (ovp->show_partial_btn, ovp, NULL);
7312   SetStatus (ovp->show_partial_btn, TRUE);
7313 
7314   g = HiddenGroup (w, 2, 0, NULL);
7315 	ic = IconButton(g, 500, 240,
7316 	DrawIcon, NULL, myclick, NULL, NULL, myrelease);
7317 	if (ovp->select_orf != NULL) {
7318 	}
7319 	ovp->icon = ic;
7320   SetObjectExtra (ic, ovp, NULL);
7321   k = HiddenGroup (g, 0, 2, NULL);
7322   ovp->orf_order = HiddenGroup (k, 2, 0, ReorderOrfs);
7323   RadioButton (ovp->orf_order, "Order by Length");
7324   RadioButton (ovp->orf_order, "Order by Start");
7325   SetValue (ovp->orf_order, 1);
7326   SortOrfs (ovp);
7327   SetObjectExtra (ovp->orf_order, ovp, NULL);
7328 	ovp->doc = DocumentPanel(k, 10 * stdCharWidth, 240);
7329     SetObjectExtra (ovp->doc, ovp, NULL);
7330 /****/
7331   	ovp->par.openSpace = FALSE;
7332   	ovp->par.keepWithNext = 1;
7333   	ovp->par.keepTogether = 1;
7334 	ovp->par.newPage  = 1;
7335   	ovp->par.tabStops     = 1;
7336 
7337   	PopulateOrfList (ovp);
7338 /****/
7339 	SetDocNotify(ovp->doc, notify);
7340 	/*ovp = (OrfViewFormPtr) GetObjectExtra(ic);*/
7341     omp = ObjMgrGet ();
7342     if (omp != NULL) {
7343 		ompp = ObjMgrProcFind (omp, 0, "ORF Finder", OMPROC_FILTER);
7344 		if (ompp != NULL) {
7345 			ovp->procid = ompp->procid;
7346 			ovp->proctype = OMPROC_FILTER;
7347 			ovp->userkey = OMGetNextUserKey ();
7348 			omudp = ObjMgrAddUserData (ovp->input_entityID, ompp->procid,
7349 	                           OMPROC_FILTER, ovp->userkey);
7350 			if (omudp != NULL) {
7351 				omudp->userdata.ptrvalue = (Pointer) ovp;
7352 				omudp->messagefunc = OrfViewerMsgFunc;
7353 			}
7354 		}
7355 	}
7356 	RealizeWindow (w);
7357 	Show(w);
7358 	ArrowCursor ();
7359 	Update ();
7360 	if (ovp->standAlone) {
7361 		ProcessEvents();
7362 	} else {
7363 		return;
7364 	}
7365 }
7366 
7367 typedef struct mergedata {
7368   SeqLocPtr     slp;
7369   Boolean       fuse;
7370 } MergeData, PNTR MergeDataPtr;
7371 
AddToSeqLoc(GatherContextPtr gcp)7372 static Boolean AddToSeqLoc (GatherContextPtr gcp)
7373 
7374 {
7375   BioseqPtr     bsp;
7376   MergeDataPtr  mdp;
7377   SeqFeatPtr    sfp;
7378   SeqLocPtr     slp;
7379 
7380   mdp = (MergeDataPtr) gcp->userdata;
7381   if (mdp == NULL) return TRUE;
7382   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
7383   sfp = (SeqFeatPtr) gcp->thisitem;
7384   if (sfp == NULL || sfp->location == NULL) return TRUE;
7385   bsp = GetBioseqGivenSeqLoc (sfp->location, gcp->entityID);
7386   if (bsp == NULL) return TRUE;
7387   slp = SeqLocMerge (bsp, sfp->location, mdp->slp, FALSE, mdp->fuse, FALSE);
7388   mdp->slp = SeqLocFree (mdp->slp);
7389   mdp->slp = slp;
7390   return TRUE;
7391 }
7392 
OrfFindFunc(Pointer data)7393 static Int2 LIBCALLBACK OrfFindFunc (Pointer data)
7394 
7395 {
7396   BioseqPtr         bsp;
7397   OMProcControlPtr  ompcp;
7398 
7399 
7400         ompcp = (OMProcControlPtr) data;   /* always do this cast */
7401 
7402         if (ompcp == NULL || ompcp->input_itemtype == 0)
7403                 return OM_MSG_RET_ERROR;
7404 
7405         switch (ompcp->input_itemtype)
7406         {
7407                 case OBJ_BIOSEQ:
7408                         bsp = (BioseqPtr) ompcp->input_data;
7409                 break;
7410                 default:
7411                         return OM_MSG_RET_ERROR;
7412         }
7413 
7414         LaunchOrfViewer (bsp, ompcp->input_entityID, ompcp->input_itemID, FALSE);
7415         return OM_MSG_RET_DONE;
7416 }
7417 
MergeSelectedFeatureIntervals(Boolean fuse)7418 static SeqLocPtr MergeSelectedFeatureIntervals (Boolean fuse)
7419 
7420 {
7421   MergeData     md;
7422   SelStructPtr  sel;
7423 
7424   md.slp = NULL;
7425   md.fuse = fuse;
7426   for (sel = ObjMgrGetSelected (); sel != NULL; sel = sel->next) {
7427     GatherItem (sel->entityID, sel->itemID, sel->itemtype,
7428                 (Pointer) &md, AddToSeqLoc);
7429   }
7430   return md.slp;
7431 }
7432 
IntervalCombineFunc(Pointer data)7433 static Int2 LIBCALLBACK IntervalCombineFunc (Pointer data)
7434 
7435 {
7436   OMProcControlPtr  ompcp;
7437   SeqLocPtr         slp;
7438 
7439   ompcp = (OMProcControlPtr) data;
7440   if (ompcp == NULL) return OM_MSG_RET_ERROR;
7441   slp = MergeSelectedFeatureIntervals (FALSE);
7442   if (slp == NULL) return OM_MSG_RET_ERROR;
7443   ObjMgrRegister (OBJ_SEQLOC, (Pointer) slp);
7444   return OM_MSG_RET_DONE;
7445 }
7446 
IntervalCombineAndFuseFunc(Pointer data)7447 static Int2 LIBCALLBACK IntervalCombineAndFuseFunc (Pointer data)
7448 
7449 {
7450   OMProcControlPtr  ompcp;
7451   SeqLocPtr         slp;
7452 
7453   ompcp = (OMProcControlPtr) data;
7454   if (ompcp == NULL) return OM_MSG_RET_ERROR;
7455   slp = MergeSelectedFeatureIntervals (TRUE);
7456   if (slp == NULL) return OM_MSG_RET_ERROR;
7457   ObjMgrRegister (OBJ_SEQLOC, (Pointer) slp);
7458   return OM_MSG_RET_DONE;
7459 }
7460 
7461 static CharPtr objmgrtypestrs [] = {
7462   "OBJ_ALL", "OBJ_SEQENTRY", "OBJ_BIOSEQ", "OBJ_BIOSEQSET", "OBJ_SEQDESC",
7463   "OBJ_SEQANNOT", "OBJ_ANNOTDESC", "OBJ_SEQFEAT", "OBJ_SEQALIGN", "OBJ_SEQGRAPH",
7464   "OBJ_SEQSUB", "OBJ_SUBMIT_BLOCK", "OBJ_SEQSUB_CONTACT", "13", "OBJ_BIOSEQ_MAPFEAT",
7465   "OBJ_BIOSEQ_SEG", "OBJ_SEQHIST", "OBJ_SEQHIST_ALIGN", "OBJ_BIOSEQ_DELTA", "19",
7466   "OBJ_PUB", "OBJ_SEQFEAT_CIT", "OBJ_SEQSUB_CIT", "OBJ_MEDLINE_ENTRY", "OBJ_PUB_SET",
7467   "OBJ_SEQLOC", "OBJ_SEQID", "OBJ_SEQCODE", "OBJ_SEQCODE_SET", "OBJ_GENETIC_CODE",
7468   "OBJ_GENETIC_CODE_SET", "OBJ_TEXT_REPORT", "OBJ_FASTA", "OBJ_VIBRANT_PICTURE", "OBJ_PROJECT"
7469 };
7470 
7471 static CharPtr temploadstrs [] = {
7472   "TL_NOT_TEMP", "TL_LOADED", "TL_CACHED"
7473 };
7474 
7475 static CharPtr proctypestrs [] = {
7476   "0", "OMPROC_OPEN", "OMPROC_DELETE", "OMPROC_VIEW", "OMPROC_EDIT",
7477   "OMPROC_SAVE", "OMPROC_CUT", "OMPROC_COPY", "OMPROC_PASTE", "OMPROC_ANALYZE",
7478   "OMPROC_FIND", "OMPROC_REPLACE", "OMPROC_FILTER", "OMPROC_FETCH",
7479 };
7480 
PrintABool(FILE * fp,CharPtr str,Boolean val)7481 static void PrintABool (FILE *fp, CharPtr str, Boolean val)
7482 
7483 {
7484   if (val) {
7485     fprintf (fp, "%s TRUE\n", str);
7486   } else {
7487     fprintf (fp, "%s FALSE\n", str);
7488   }
7489 }
7490 
7491 Int2 LIBCALLBACK VSMPictMsgFunc PROTO((OMMsgStructPtr ommsp));
7492 
ReportOnEntity(ObjMgrDataPtr omdp,ObjMgrPtr omp,Boolean selected,Uint4 itemID,Uint2 itemtype,Int2 index,FILE * fp)7493 static void ReportOnEntity (ObjMgrDataPtr omdp, ObjMgrPtr omp, Boolean selected, Uint4 itemID,
7494                             Uint2 itemtype, Int2 index, FILE *fp)
7495 
7496 {
7497   BioseqPtr      bsp;
7498   BioseqSetPtr   bssp;
7499   Char           buf [50];
7500   OMUserDataPtr  omudp;
7501   VSMPictPtr     vsmpp;
7502 
7503   if (omdp == NULL || fp == NULL) return;
7504   if (selected) {
7505     fprintf (fp, "Data Element\n\n");
7506     fprintf (fp, "  EntityID %d selected\n", (int) omdp->EntityID);
7507     fprintf (fp, "  ItemID %d, Itemtype %d\n", (int) itemID, (int) itemtype);
7508   } else if (omdp->parentptr == NULL) {
7509     fprintf (fp, "Top Data Element %d\n\n", (int) index);
7510     fprintf (fp, "  EntityID %d\n", (int) omdp->EntityID);
7511   } else {
7512     fprintf (fp, "Inner Data Element %d\n\n", (int) index);
7513     fprintf (fp, "  EntityID %d\n", (int) omdp->EntityID);
7514   }
7515   if (omdp->datatype < OBJ_MAX) {
7516     fprintf (fp, "  Datatype %s", objmgrtypestrs [omdp->datatype]);
7517     if (omdp->datatype == OBJ_BIOSEQ) {
7518       bsp = (BioseqPtr) omdp->dataptr;
7519       if (bsp != NULL) {
7520         SeqIdWrite (bsp->id, buf, PRINTID_FASTA_LONG, sizeof (buf) - 1);
7521         fprintf (fp, " %s, length %ld", buf, (long) bsp->length);
7522       }
7523     } else if (omdp->datatype == OBJ_BIOSEQSET) {
7524       bssp = (BioseqSetPtr) omdp->dataptr;
7525       if (bssp != NULL) {
7526         fprintf (fp, " class %d", (int) bssp->_class);
7527       }
7528     }
7529     fprintf (fp, "\n");
7530   } else {
7531     fprintf (fp, "  Unregistered datatype %d\n", (int) omdp->datatype);
7532   }
7533   fprintf (fp, "  Lockcnt %d\n", (int) omdp->lockcnt);
7534   if (omdp->tempload < 3) {
7535     fprintf (fp, "  Tempload %s\n", temploadstrs [omdp->tempload]);
7536   } else {
7537     fprintf (fp, "  Unrecognized tempload %d\n", (int) omdp->tempload);
7538   }
7539   PrintABool (fp, "  Clipboard", omdp->clipboard);
7540   PrintABool (fp, "  Dirty", omdp->dirty);
7541   PrintABool (fp, "  Being_freed", omdp->being_freed);
7542   PrintABool (fp, "  Free", omdp->free);
7543   fprintf (fp, "\n");
7544   for (omudp = omdp->userdata; omudp != NULL; omudp = omudp->next) {
7545     if (omudp->proctype <= OMPROC_MAX) {
7546       fprintf (fp, "    Proctype %s\n", proctypestrs [omudp->proctype]);
7547     } else {
7548       fprintf (fp, "    Unrecognized proctype %d\n", (int) omudp->proctype);
7549     }
7550     fprintf (fp, "    Procid %d\n", (int) omudp->procid);
7551     fprintf (fp, "    Userkey %d\n", (int) omudp->userkey);
7552     if (omudp->messagefunc == VSMPictMsgFunc) {
7553       vsmpp = (VSMPictPtr) omudp->userdata.ptrvalue;
7554       if (vsmpp != NULL) {
7555         if (vsmpp->s != NULL) {
7556           fprintf (fp, "    VSMPictPtr segment not NULL\n");
7557         } else {
7558           fprintf (fp, "    VSMPictPtr segment is NULL\n");
7559         }
7560       }
7561     }
7562     fprintf (fp, "\n");
7563   }
7564 }
7565 
DesktopReportFunc(Pointer data)7566 static Int2 LIBCALLBACK DesktopReportFunc (Pointer data)
7567 
7568 {
7569   FILE           *fp;
7570   Uint4          j;
7571   Uint4          num;
7572   ObjMgrPtr      omp;
7573   ObjMgrDataPtr  omdp;
7574   ObjMgrDataPtr  PNTR omdpp;
7575   Char           path [PATH_MAX];
7576   SelStructPtr   sel;
7577 
7578   omp = ObjMgrGet ();
7579   if (omp == NULL) return OM_MSG_RET_DONE;
7580   TmpNam (path);
7581   fp = FileOpen (path, "w");
7582   fprintf (fp, "Object Manager\n\n");
7583   fprintf (fp, "  HighestEntityID %d\n", (int) omp->HighestEntityID);
7584   fprintf (fp, "  Totobj %d\n", (int) omp->totobj);
7585   fprintf (fp, "  Currobj %d\n", (int) omp->currobj);
7586   fprintf (fp, "  Maxtemp %d\n", (int) omp->maxtemp);
7587   fprintf (fp, "  Tempcnt %d\n", (int) omp->tempcnt);
7588   fprintf (fp, "  Hold %d\n", (int) omp->hold);
7589   PrintABool (fp, "  Reaping", omp->reaping);
7590   PrintABool (fp, "  Is_write_locked", omp->is_write_locked);
7591   fprintf (fp, "\n");
7592   sel = ObjMgrGetSelected ();
7593   if (sel != NULL) {
7594     omdp = ObjMgrGetData (sel->entityID);
7595     ReportOnEntity (omdp, omp, TRUE, sel->itemID, sel->itemtype, 0, fp);
7596   } else {
7597     num = omp->currobj;
7598     for (j = 0, omdpp = omp->datalist; j < num && omdpp != NULL; j++, omdpp++) {
7599       omdp = *omdpp;
7600       if (omdp->parentptr == NULL) {
7601         ReportOnEntity (omdp, omp, FALSE, 0, 0, j + 1, fp);
7602       }
7603     }
7604     for (j = 0, omdpp = omp->datalist; j < num && omdpp != NULL; j++, omdpp++) {
7605       omdp = *omdpp;
7606       if (omdp->parentptr != NULL) {
7607         ReportOnEntity (omdp, omp, FALSE, 0, 0, j + 1, fp);
7608       }
7609     }
7610   }
7611   FileClose (fp);
7612   LaunchGeneralTextViewer (path, "Object Manager Report");
7613   FileRemove (path);
7614   return OM_MSG_RET_DONE;
7615 }
7616 
7617 
MRnaFromCdsCallback(SeqFeatPtr sfp,Pointer userdata)7618 static void MRnaFromCdsCallback (SeqFeatPtr sfp, Pointer userdata)
7619 {
7620   Boolean       process_this_one = FALSE;
7621   Boolean       any_feat_selected = FALSE;
7622   SelStructPtr  sel;
7623   Uint2Ptr      entityIDptr;
7624   Uint2         entityID;
7625   SeqFeatPtr    mrna;
7626   SeqMgrFeatContext context;
7627   ValNode           field;
7628   FeatureFieldPtr   ff;
7629   CharPtr           feat_product, mrna_product;
7630 
7631   if (sfp == NULL || sfp->idx.subtype != FEATDEF_CDS || userdata == NULL) return;
7632   if (IsMrnaSequence(BioseqFindFromSeqLoc(sfp->location))) {
7633     return;
7634   }
7635   entityIDptr = (Uint2Ptr) userdata;
7636   entityID = *entityIDptr;
7637 
7638   sel = ObjMgrGetSelected ();
7639   if (sel == NULL)
7640   {
7641   	process_this_one = TRUE;
7642   }
7643   else
7644   {
7645     while (sel != NULL && sel->itemID != sfp->idx.itemID)
7646     {
7647       if (sel->itemtype == OBJ_SEQFEAT) {
7648         any_feat_selected = TRUE;
7649       }
7650       sel = sel->next;
7651     }
7652     if (sel != NULL || !any_feat_selected)
7653     {
7654       process_this_one = TRUE;
7655     }
7656   }
7657   if (process_this_one)
7658   {
7659     mrna = SeqMgrGetLocationSupersetmRNA (sfp->location, &context);
7660     if (mrna == NULL) {
7661       mrna = SeqMgrGetOverlappingmRNA (sfp->location, &context);
7662     }
7663 
7664     if (mrna != NULL) {
7665       ff = FeatureFieldNew ();
7666       ff->type = Macro_feature_type_any;
7667       ValNodeAddInt (&(ff->field), FeatQualChoice_legal_qual, Feat_qual_legal_product);
7668       field.choice = FieldType_feature_field;
7669       field.data.ptrvalue = ff;
7670       field.next = NULL;
7671       feat_product = GetFieldValueForObject (OBJ_SEQFEAT, sfp, &field, NULL);
7672       mrna_product = GetFieldValueForObject (OBJ_SEQFEAT, mrna, &field, NULL);
7673       if (StringCmp (feat_product, mrna_product) == 0 || ProductsMatchForRefSeq(feat_product, mrna_product)) {
7674         process_this_one = FALSE;
7675       }
7676       feat_product = MemFree (feat_product);
7677       mrna_product = MemFree (mrna_product);
7678       ff = FeatureFieldFree (ff);
7679     }
7680   }
7681 
7682   if (process_this_one)
7683   {
7684     AddmRNAForCDS (sfp);
7685   }
7686 }
7687 
MRnaFromCdsProc(Uint2 entityID)7688 extern void MRnaFromCdsProc (Uint2 entityID)
7689 
7690 {
7691   SeqEntryPtr   sep;
7692 
7693   if (entityID == 0) return;
7694 
7695   sep = GetTopSeqEntryForEntityID (entityID);
7696   VisitFeaturesInSep (sep, (Pointer) &entityID, MRnaFromCdsCallback);
7697   ObjMgrSetDirtyFlag (entityID, TRUE);
7698   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
7699 }
7700 
7701 
AddBspToVnpCallback(SeqEntryPtr sep,Pointer mydata,Int4 index,Int2 indent)7702 static void AddBspToVnpCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
7703 
7704 {
7705   BioseqPtr        bsp;
7706   ValNodePtr PNTR  vnpp;
7707 
7708   vnpp = (ValNodePtr PNTR) mydata;
7709   if (IS_Bioseq (sep)) {
7710     bsp = (BioseqPtr) sep->data.ptrvalue;
7711     if (bsp != NULL && ISA_na (bsp->mol)) {
7712       ValNodeAddPointer (vnpp, 0, (Pointer) bsp);
7713     }
7714   }
7715 }
7716 
AddBspToVnp(GatherContextPtr gcp)7717 static Boolean AddBspToVnp (GatherContextPtr gcp)
7718 
7719 {
7720   BioseqPtr        bsp;
7721   BioseqSetPtr     bssp;
7722   SeqEntryPtr      sep;
7723   ValNodePtr PNTR  vnpp;
7724 
7725   vnpp = (ValNodePtr PNTR) gcp->userdata;
7726   if (vnpp == NULL) return TRUE;
7727   bsp = NULL;
7728   if (gcp->thistype == OBJ_BIOSEQ) {
7729     bsp = (BioseqPtr) gcp->thisitem;
7730   } else if (gcp->thistype == OBJ_BIOSEQSET) {
7731     bssp = (BioseqSetPtr) gcp->thisitem;
7732     if (bssp != NULL) {
7733       sep = SeqMgrGetSeqEntryForData (bssp);
7734       if (sep != NULL) {
7735         SeqEntryExplore (sep, (Pointer) vnpp, AddBspToVnpCallback);
7736       }
7737     }
7738     return TRUE;
7739   } else return TRUE;
7740   if (bsp == NULL) return TRUE;
7741   ValNodeAddPointer (vnpp, 0, (Pointer) bsp);
7742   return TRUE;
7743 }
7744 
7745 
RevCompBioseqListInteractive(ValNodePtr bsp_list,Uint2 entityID,BioseqFunc func,Boolean revCompFeats,Boolean check_for_aln)7746 static void RevCompBioseqListInteractive (ValNodePtr bsp_list, Uint2 entityID, BioseqFunc func,
7747                                Boolean revCompFeats, Boolean check_for_aln)
7748 {
7749   ValNodePtr aln_bsp = NULL, vnp;
7750   ValNodeBlock msg_block;
7751   BioseqPtr    bsp;
7752   Char         id_str[255];
7753   CharPtr      msg;
7754   MsgAnswer    ans;
7755 
7756   if (bsp_list == NULL) return;
7757 
7758   if (func != NULL && check_for_aln) {
7759     aln_bsp = ListSequencesWithAlignments (bsp_list);
7760     if (aln_bsp != NULL) {
7761       InitValNodeBlock (&msg_block, NULL);
7762       for (vnp = aln_bsp; vnp != NULL; vnp = vnp->next) {
7763         bsp = (BioseqPtr) vnp->data.ptrvalue;
7764         SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), id_str, PRINTID_REPORT, sizeof (id_str) - 1);
7765         ValNodeAddPointerToEnd (&msg_block, 0, StringSave (id_str));
7766       }
7767   	  msg = CreateListMessage ("Sequence",
7768   	                           msg_block.head->next == NULL
7769   	                           ? " is in an alignment, which will become invalid.  Do you want to remove the alignment?"
7770   	                           : " are in alignments, which will become invalid unless all of the sequences in these alignments are reversed.  Do you want to remove the alignments?",
7771   	                           msg_block.head);
7772   	  msg_block.head = ValNodeFreeData (msg_block.head);
7773       ans = Message (MSG_YNC, msg);
7774       msg = MemFree (msg);
7775       if (ans == ANS_YES) {
7776         /* remove the alignments */
7777         for (vnp = aln_bsp; vnp != NULL; vnp = vnp->next) {
7778           bsp = vnp->data.ptrvalue;
7779           RemoveAlignmentsWithSequence (bsp, bsp->idx.entityID);
7780         }
7781         DeleteMarkedObjects (entityID, 0, NULL);
7782       } else if (ans == ANS_CANCEL) {
7783         aln_bsp = ValNodeFree (aln_bsp);
7784         return;
7785       }
7786     }
7787   }
7788 
7789   RevCompBioseqList (bsp_list, entityID, func, revCompFeats, check_for_aln);
7790 
7791   /* now also reverse quality scores - SQD-1271 */
7792   for (vnp = bsp_list; vnp != NULL; vnp = vnp->next)  {
7793     ReverseQualityScores ((BioseqPtr) vnp->data.ptrvalue);
7794   }
7795 
7796   /* flip alignments if all sequences in alignment were flipped */
7797   if (aln_bsp != NULL) {
7798     VisitAnnotsInSep (GetTopSeqEntryForEntityID (entityID), aln_bsp, FlipEntireAlignmentIfAllSequencesFlipped);
7799     aln_bsp = ValNodeFree (aln_bsp);
7800   }
7801 
7802   ObjMgrSetDirtyFlag (entityID, TRUE);
7803   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
7804 }
7805 
7806 
ProcessMultipleBioseqFunctions(OMProcControlPtr ompcp,BioseqFunc func,Boolean revCompFeats,Boolean check_for_aln)7807 static void ProcessMultipleBioseqFunctions (OMProcControlPtr ompcp, BioseqFunc func,
7808                                             Boolean revCompFeats, Boolean check_for_aln)
7809 
7810 {
7811   ValNodePtr    head;
7812   SelStructPtr  sel;
7813 
7814   if (ompcp == NULL || ompcp->input_entityID == 0 || func == NULL) return;
7815   head = NULL;
7816   for (sel = ObjMgrGetSelected (); sel != NULL; sel = sel->next) {
7817     GatherItem (sel->entityID, sel->itemID, sel->itemtype,
7818                 (Pointer) &head, AddBspToVnp);
7819   }
7820   if (head == NULL) return;
7821 
7822   RevCompBioseqListInteractive (head, ompcp->input_entityID, func, revCompFeats, check_for_aln);
7823   head = ValNodeFree (head);
7824 }
7825 
7826 
7827 typedef struct revcompbyidfrm {
7828   FORM_MESSAGE_BLOCK
7829   DialoG constraint;
7830   ButtoN revcomp_seq;
7831   ButtoN reverse_feats;
7832   ButtoN accept;
7833 } RevCompByIdFrmData, PNTR RevCompByIdFrmPtr;
7834 
7835 
ChangeRevComp(ButtoN b)7836 static void ChangeRevComp (ButtoN b)
7837 {
7838   RevCompByIdFrmPtr f;
7839 
7840   f = (RevCompByIdFrmPtr) GetObjectExtra (b);
7841   if (f == NULL) return;
7842 
7843   if (!GetStatus (f->revcomp_seq) && !GetStatus (f->reverse_feats))
7844   {
7845     Disable (f->accept);
7846   }
7847   else
7848   {
7849     Enable (f->accept);
7850   }
7851 }
7852 
7853 
DoRevComp(ButtoN b)7854 static void DoRevComp (ButtoN b)
7855 {
7856   RevCompByIdFrmPtr f;
7857   ConstraintChoiceSetPtr constraint;
7858   ValNodePtr            bsp_list;
7859   SeqEntryPtr           sep;
7860 
7861   f = (RevCompByIdFrmPtr) GetObjectExtra (b);
7862   if (f == NULL) return;
7863 
7864   sep = GetTopSeqEntryForEntityID (f->input_entityID);
7865   constraint = DialogToPointer (f->constraint);
7866   bsp_list = GetSequenceListForConstraint (sep, constraint);
7867   constraint = ConstraintChoiceSetFree (constraint);
7868 
7869   if (bsp_list == NULL)
7870   {
7871     Message (MSG_ERROR, "No sequences match constraint!");
7872   }
7873   else
7874   {
7875     RevCompBioseqListInteractive (bsp_list, f->input_entityID,
7876                        GetStatus (f->revcomp_seq) ? BioseqRevComp : NULL,
7877                        GetStatus (f->reverse_feats), GetStatus (f->revcomp_seq));
7878     Remove (f->form);
7879   }
7880   bsp_list = ValNodeFree (bsp_list);
7881 }
7882 
BioseqRevCompByIDForEntityID(Uint2 entityID)7883 static Int2 LIBCALLBACK BioseqRevCompByIDForEntityID (Uint2 entityID)
7884 
7885 {
7886   GrouP            c;
7887   GrouP            h;
7888   RevCompByIdFrmPtr f;
7889   WindoW           w;
7890 
7891   f = (RevCompByIdFrmPtr) MemNew (sizeof (RevCompByIdFrmData));
7892   if (f == NULL) return OM_MSG_RET_ERROR;
7893   w = FixedWindow (-50, -33, -10, -10, "Reverse Complement", StdCloseWindowProc);
7894   SetObjectExtra (w, f, StdCleanupFormProc);
7895   f->form = (ForM) w;
7896   f->formmessage = NULL;
7897 
7898   f->input_entityID = entityID;
7899 
7900   h = HiddenGroup (w, -1, 0, NULL);
7901   f->revcomp_seq = CheckBox (h, "Reverse complement sequence", ChangeRevComp);
7902   SetStatus (f->revcomp_seq, TRUE);
7903   f->reverse_feats = CheckBox (h, "Reverse features", ChangeRevComp);
7904   SetStatus (f->reverse_feats, TRUE);
7905 
7906   f->constraint = ComplexConstraintDialog (h, NULL, NULL);
7907   ChangeComplexConstraintFieldType (f->constraint, FieldType_molinfo_field, NULL, Macro_feature_type_any);
7908 
7909   c = HiddenGroup (h, 2, 0, NULL);
7910   f->accept = DefaultButton (c, "Accept", DoRevComp);
7911   SetObjectExtra (f->accept, f, NULL);
7912   PushButton (c, "Cancel", StdCancelButtonProc);
7913   AlignObjects (ALIGN_CENTER, (HANDLE) f->constraint,
7914                               (HANDLE) f->revcomp_seq,
7915                               (HANDLE) f->reverse_feats,
7916                               (HANDLE) c, NULL);
7917   RealizeWindow (w);
7918   Show (w);
7919   Update ();
7920   return OM_MSG_RET_DONE;
7921 }
7922 
7923 
BioseqRevCompByID(Pointer data)7924 static Int2 LIBCALLBACK BioseqRevCompByID (Pointer data)
7925 
7926 {
7927   OMProcControlPtr ompcp;
7928 
7929   ompcp = (OMProcControlPtr) data;
7930   if (ompcp == NULL) return OM_MSG_RET_ERROR;
7931 
7932   return BioseqRevCompByIDForEntityID (ompcp->input_entityID);
7933 }
7934 
7935 
BioseqRevCompByIDMenuItem(IteM i)7936 extern void BioseqRevCompByIDMenuItem (IteM i)
7937 {
7938   BaseFormPtr   bfp;
7939 
7940 #ifdef WIN_MAC
7941   bfp = currentFormDataPtr;
7942 #else
7943   bfp = GetObjectExtra (i);
7944 #endif
7945   if (bfp == NULL) return;
7946 
7947   BioseqRevCompByIDForEntityID (bfp->input_entityID);
7948 }
7949 
7950 
DoRevQualScores(ButtoN b)7951 static void DoRevQualScores (ButtoN b)
7952 {
7953   RevCompByIdFrmPtr f;
7954   ConstraintChoiceSetPtr scp;
7955   ValNodePtr             bsp_list, vnp;
7956   SeqEntryPtr            sep;
7957 
7958   f = (RevCompByIdFrmPtr) GetObjectExtra (b);
7959   if (f == NULL) return;
7960 
7961   sep = GetTopSeqEntryForEntityID (f->input_entityID);
7962   scp = DialogToPointer (f->constraint);
7963   bsp_list = GetSequenceListForConstraint (sep, scp);
7964   scp = ConstraintChoiceSetFree (scp);
7965 
7966   if (bsp_list == NULL)
7967   {
7968     Message (MSG_ERROR, "No sequences match constraint!");
7969   }
7970   else
7971   {
7972     for (vnp = bsp_list; vnp != NULL; vnp = vnp->next)
7973     {
7974       ReverseQualityScores ((BioseqPtr) vnp->data.ptrvalue);
7975     }
7976     ObjMgrSetDirtyFlag (f->input_entityID, TRUE);
7977     ObjMgrSendMsg (OM_MSG_UPDATE, f->input_entityID, 0, 0);
7978     Remove (f->form);
7979     Update();
7980   }
7981   bsp_list = ValNodeFree (bsp_list);
7982 }
7983 
BioseqRevQualScoresForEntityID(Uint2 entityID)7984 static Int2 LIBCALLBACK BioseqRevQualScoresForEntityID (Uint2 entityID)
7985 
7986 {
7987   GrouP            c;
7988   GrouP            h;
7989   RevCompByIdFrmPtr f;
7990   WindoW           w;
7991 
7992   f = (RevCompByIdFrmPtr) MemNew (sizeof (RevCompByIdFrmData));
7993   if (f == NULL) return OM_MSG_RET_ERROR;
7994   w = FixedWindow (-50, -33, -10, -10, "Reverse Quality Scores", StdCloseWindowProc);
7995   SetObjectExtra (w, f, StdCleanupFormProc);
7996   f->form = (ForM) w;
7997   f->formmessage = NULL;
7998 
7999   f->input_entityID = entityID;
8000 
8001   h = HiddenGroup (w, -1, 0, NULL);
8002 
8003   f->constraint = ComplexConstraintDialog (h, NULL, NULL);
8004   ChangeComplexConstraintFieldType (f->constraint, FieldType_molinfo_field, NULL, Macro_feature_type_any);
8005 
8006   c = HiddenGroup (h, 2, 0, NULL);
8007   f->accept = DefaultButton (c, "Accept", DoRevQualScores);
8008   SetObjectExtra (f->accept, f, NULL);
8009   PushButton (c, "Cancel", StdCancelButtonProc);
8010   AlignObjects (ALIGN_CENTER, (HANDLE) f->constraint,
8011                               (HANDLE) c, NULL);
8012   RealizeWindow (w);
8013   Show (w);
8014   Update ();
8015   return OM_MSG_RET_DONE;
8016 }
8017 
8018 
BioseqRevQualScoresMenuItem(IteM i)8019 extern void BioseqRevQualScoresMenuItem (IteM i)
8020 {
8021   BaseFormPtr   bfp;
8022 
8023 #ifdef WIN_MAC
8024   bfp = currentFormDataPtr;
8025 #else
8026   bfp = GetObjectExtra (i);
8027 #endif
8028   if (bfp == NULL) return;
8029 
8030   BioseqRevQualScoresForEntityID (bfp->input_entityID);
8031 }
8032 
8033 
ReverseComplementBioseqAndFeats(BioseqPtr bsp,Uint2 entityID)8034 extern void ReverseComplementBioseqAndFeats (BioseqPtr bsp, Uint2 entityID)
8035 {
8036   SeqEntryPtr sep;
8037 
8038   if (bsp == NULL) return;
8039   sep = GetTopSeqEntryForEntityID (entityID);
8040   if (sep != NULL) {
8041     BioseqRevComp (bsp);
8042     SeqEntryExplore (sep, (Pointer) bsp, RevCompFeats);
8043   }
8044 }
8045 
RevCompFuncFeat(Pointer data)8046 static Int2 LIBCALLBACK RevCompFuncFeat (Pointer data)
8047 
8048 {
8049   ProcessMultipleBioseqFunctions ((OMProcControlPtr) data, BioseqRevComp, TRUE, TRUE);
8050   return OM_MSG_RET_DONE;
8051 }
8052 
RevCompFunc(Pointer data)8053 static Int2 LIBCALLBACK RevCompFunc (Pointer data)
8054 
8055 {
8056   ProcessMultipleBioseqFunctions ((OMProcControlPtr) data, BioseqRevComp, FALSE, TRUE);
8057   return OM_MSG_RET_DONE;
8058 }
8059 
RevFunc(Pointer data)8060 static Int2 LIBCALLBACK RevFunc (Pointer data)
8061 
8062 {
8063   ProcessMultipleBioseqFunctions ((OMProcControlPtr) data, BioseqReverse, FALSE, TRUE);
8064   return OM_MSG_RET_DONE;
8065 }
8066 
CompFunc(Pointer data)8067 static Int2 LIBCALLBACK CompFunc (Pointer data)
8068 
8069 {
8070   ProcessMultipleBioseqFunctions ((OMProcControlPtr) data, BioseqComplement, FALSE, FALSE);
8071   return OM_MSG_RET_DONE;
8072 }
8073 
8074 typedef struct orphandata {
8075   ValNodePtr  bspfromcds;
8076   ValNodePtr  bspinentry;
8077 } OrphanData, PNTR OrphanDataPtr;
8078 
GetCdsProducts(SeqEntryPtr sep,Pointer mydata,Int4 index,Int2 indent)8079 static void GetCdsProducts (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
8080 
8081 {
8082   BioseqPtr      bsp;
8083   BioseqSetPtr   bssp;
8084   OrphanDataPtr  odp;
8085   SeqAnnotPtr    sap;
8086   SeqFeatPtr     sfp;
8087   SeqIdPtr       sip;
8088 
8089   if (mydata == NULL) return;
8090   if (sep == NULL || sep->data.ptrvalue == NULL) return;
8091   odp = (OrphanDataPtr) mydata;
8092   if (IS_Bioseq (sep)) {
8093     bsp = (BioseqPtr) sep->data.ptrvalue;
8094     sap = bsp->annot;
8095     if (ISA_aa (bsp->mol)) {
8096       ValNodeAddPointer (&(odp->bspinentry), 0, (Pointer) bsp);
8097     }
8098   } else if (IS_Bioseq_set (sep)) {
8099     bssp = (BioseqSetPtr) sep->data.ptrvalue;
8100     sap = bssp->annot;
8101   } else return;
8102   while (sap != NULL) {
8103     if (sap->type == 1) {
8104       sfp = (SeqFeatPtr) sap->data;
8105       while (sfp != NULL) {
8106         if (sfp->data.choice == SEQFEAT_CDREGION) {
8107           if (sfp->product != NULL) {
8108             sip = SeqLocId (sfp->product);
8109             if (sip != NULL) {
8110               bsp = BioseqFind (sip);
8111               if (bsp != NULL) {
8112                 ValNodeAddPointer (&(odp->bspfromcds), 0, (Pointer) bsp);
8113               }
8114             }
8115           }
8116         }
8117         sfp = sfp->next;
8118       }
8119     }
8120     sap = sap->next;
8121   }
8122 }
8123 
SortByVnpDataPtrvalue(VoidPtr ptr1,VoidPtr ptr2)8124 static int LIBCALLBACK SortByVnpDataPtrvalue (VoidPtr ptr1, VoidPtr ptr2)
8125 
8126 {
8127   ValNodePtr   vnp1;
8128   ValNodePtr   vnp2;
8129 
8130   if (ptr1 != NULL && ptr2 != NULL) {
8131     vnp1 = *((ValNodePtr PNTR) ptr1);
8132     vnp2 = *((ValNodePtr PNTR) ptr2);
8133     if (vnp1 != NULL && vnp2 != NULL) {
8134       if (vnp1->data.ptrvalue > vnp2->data.ptrvalue) {
8135         return 1;
8136       } else if (vnp1->data.ptrvalue < vnp2->data.ptrvalue) {
8137         return -1;
8138       } else {
8139         return 0;
8140       }
8141     } else {
8142       return 0;
8143     }
8144   } else {
8145     return 0;
8146   }
8147 }
8148 
RemoveOrphanProteins(Uint2 entityID,SeqEntryPtr sep)8149 extern void RemoveOrphanProteins (Uint2 entityID, SeqEntryPtr sep)
8150 
8151 {
8152   Int2        doit;
8153   OrphanData  od;
8154   ValNodePtr  vnp;
8155   ValNodePtr  vnp1;
8156   ValNodePtr  vnp2;
8157   BioseqPtr   protein_bsp;
8158 
8159   if (sep == NULL || entityID == 0) return;
8160   od.bspfromcds = NULL;
8161   od.bspinentry = NULL;
8162   /* This function collects a list of all proteins in the entry
8163    * and a list of all proteins that are products of a CDS
8164    */
8165   SeqEntryExplore (sep, (Pointer) &od, GetCdsProducts);
8166 
8167   /* If there are no proteins in the entry at all, we're done */
8168   if (od.bspinentry == NULL)
8169   {
8170     ValNodeFree (od.bspinentry);
8171     return;
8172   }
8173 
8174   /* If we found any CDS product proteins, we need to sort the two
8175    * lists and mark the ones in both lists as "keep".
8176    * If there are no CDS product proteins, then all of the proteins
8177    * in the entry should be removed.
8178    */
8179   if (od.bspfromcds != NULL) {
8180     od.bspinentry = SortValNode (od.bspinentry, SortByVnpDataPtrvalue);
8181     od.bspfromcds = SortValNode (od.bspfromcds, SortByVnpDataPtrvalue);
8182     vnp1 = od.bspfromcds;
8183     vnp2 = od.bspinentry;
8184     while (vnp1 != NULL && vnp2 != NULL) {
8185       if (vnp1->data.ptrvalue < vnp2->data.ptrvalue) {
8186         vnp1 = vnp1->next;
8187       } else if (vnp2->data.ptrvalue < vnp1->data.ptrvalue) {
8188         vnp2 = vnp2->next;
8189       } else {
8190         vnp2->data.ptrvalue = NULL;
8191         vnp1 = vnp1->next;
8192         vnp2 = vnp2->next;
8193       }
8194     }
8195   }
8196 
8197   /* Now we count how many proteins are in the entry but not a
8198    * product of a CDS
8199    */
8200   doit = 0;
8201   for (vnp = od.bspinentry; vnp != NULL; vnp = vnp->next) {
8202     if (vnp->data.ptrvalue != NULL) {
8203       doit++;
8204     }
8205   }
8206   if (doit > 0) {
8207     if (Message (MSG_YN, "Do you want to remove %d orphaned proteins?", (int) doit) == ANS_YES) {
8208       vnp = od.bspinentry;
8209       while (vnp != NULL) {
8210         if (vnp->data.ptrvalue != NULL) {
8211           protein_bsp = vnp->data.ptrvalue;
8212           protein_bsp->idx.deleteme = TRUE;
8213         }
8214         vnp = vnp->next;
8215       }
8216       DeleteMarkedObjects (entityID, 0, NULL);
8217       ObjMgrSetDirtyFlag (entityID, TRUE);
8218       ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
8219     }
8220   }
8221 
8222   ValNodeFree (od.bspinentry);
8223   ValNodeFree (od.bspfromcds);
8224 }
8225 
NormalizeNucProts(Pointer data)8226 static Int2 LIBCALLBACK NormalizeNucProts (Pointer data)
8227 
8228 {
8229   OMProcControlPtr  ompcp;
8230   SeqEntryPtr       sep;
8231 
8232   ompcp = (OMProcControlPtr) data;
8233   if (ompcp == NULL) return OM_MSG_RET_ERROR;
8234   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
8235   RemoveOrphanProteins (ompcp->input_entityID, sep);
8236   RenormalizeNucProtSets (sep, TRUE);
8237   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
8238   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
8239   return OM_MSG_RET_DONE;
8240 }
8241 
RemovePopPhyMutSet(SeqEntryPtr sep,Boolean forceGBClass,Boolean forceAll)8242 static void RemovePopPhyMutSet (SeqEntryPtr sep, Boolean forceGBClass, Boolean forceAll)
8243 
8244 {
8245   SeqAnnotPtr   annot;
8246   BioseqPtr     bsp;
8247   BioseqSetPtr  bssp;
8248   ValNodePtr    descr;
8249   SeqAnnotPtr   sap;
8250   SeqEntryPtr   seqentry;
8251 
8252   if (sep == NULL || IS_Bioseq (sep)) return;
8253   bssp = (BioseqSetPtr) sep->data.ptrvalue;
8254   if (bssp == NULL) return;
8255   if (forceAll) {
8256   } else if (forceGBClass) {
8257     if ((bssp->_class < 13 || bssp->_class > 15) && bssp->_class != 7) return;
8258   } else {
8259     if (bssp->_class < 13 || bssp->_class > 15) return;
8260   }
8261   seqentry = bssp->seq_set;
8262   if (seqentry == NULL) return;
8263   if (! forceAll) {
8264     if (! forceGBClass) {
8265       if (seqentry->next != NULL) return;
8266     }
8267   }
8268   descr = bssp->descr;
8269   bssp->descr = NULL;
8270   annot = bssp->annot;
8271   bssp->annot = NULL;
8272   sep->choice = seqentry->choice;
8273   sep->data.ptrvalue = seqentry->data.ptrvalue;
8274   sep->next = seqentry->next;
8275   seqentry->data.ptrvalue = NULL;
8276   seqentry->next = NULL;
8277   bssp->seq_set = NULL;
8278   SeqEntryFree (seqentry);
8279   BioseqSetFree (bssp);
8280   sap = NULL;
8281   if (IS_Bioseq (sep)) {
8282     bsp = (BioseqPtr) sep->data.ptrvalue;
8283     ValNodeLink (&(bsp->descr), descr);
8284     if (bsp->annot == NULL) {
8285       bsp->annot = annot;
8286       annot = NULL;
8287     } else {
8288       sap = bsp->annot;
8289     }
8290   } else if (IS_Bioseq_set (sep)) {
8291     bssp = (BioseqSetPtr) sep->data.ptrvalue;
8292     ValNodeLink (&(bssp->descr), descr);
8293     if (bssp->annot == NULL) {
8294       bssp->annot = annot;
8295       annot = NULL;
8296     } else {
8297       sap = bssp->annot;
8298     }
8299   }
8300   if (sap != NULL) {
8301     while (sap->next != NULL) {
8302       sap = sap->next;
8303     }
8304     sap->next = annot;
8305   }
8306 }
8307 
InsetNewSet(BioseqSetPtr bssp,Uint1 _class)8308 NLM_EXTERN BioseqSetPtr InsetNewSet (BioseqSetPtr bssp, Uint1 _class)
8309 
8310 {
8311   BioseqSetPtr  popphymut;
8312   SeqEntryPtr   tmp;
8313 
8314   if (bssp == NULL) return NULL;
8315   popphymut = BioseqSetNew ();
8316   if (popphymut == NULL) return NULL;
8317   popphymut->_class = _class;
8318   popphymut->seq_set = bssp->seq_set;
8319   tmp = SeqEntryNew ();
8320   if (tmp == NULL) return NULL;
8321   tmp->choice = 2;
8322   tmp->data.ptrvalue = (Pointer) popphymut;
8323   bssp->seq_set = tmp;
8324   return popphymut;
8325 }
8326 
SetWithinGenBankSet(Pointer data,Uint1 _class)8327 static Int2 LIBCALLBACK SetWithinGenBankSet (Pointer data, Uint1 _class)
8328 
8329 {
8330   BioseqSetPtr      bssp;
8331   BioseqSetPtr      newbssp;
8332   ObjMgrDataPtr     omdptop;
8333   ObjMgrData        omdata;
8334   OMProcControlPtr  ompcp;
8335   Uint2             parenttype;
8336   Pointer           parentptr;
8337   SeqEntryPtr       sep;
8338 
8339   ompcp = (OMProcControlPtr) data;
8340   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
8341   switch (ompcp->input_itemtype) {
8342     case OBJ_BIOSEQ :
8343       break;
8344     case OBJ_BIOSEQSET :
8345       break;
8346     case 0 :
8347       return OM_MSG_RET_ERROR;
8348     default :
8349       break;
8350   }
8351   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
8352   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
8353   if (sep == NULL) return OM_MSG_RET_ERROR;
8354   SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
8355   GetSeqEntryParent (sep, &parentptr, &parenttype);
8356   RemoveDupGenBankSets (sep);
8357   if (IS_Bioseq_set (sep)) {
8358     bssp = (BioseqSetPtr) sep->data.ptrvalue;
8359     if (bssp != NULL) {
8360       newbssp = InsetNewSet (bssp, _class);
8361       if (newbssp != NULL) {
8362         newbssp->descr = bssp->descr;
8363         bssp->descr = NULL;
8364         newbssp->annot = bssp->annot;
8365         bssp->annot = NULL;
8366       }
8367     }
8368   }
8369   SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
8370   RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
8371   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
8372   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
8373   return OM_MSG_RET_DONE;
8374 }
8375 
PopWithinGenBankSet(Pointer data)8376 static Int2 LIBCALLBACK PopWithinGenBankSet (Pointer data)
8377 
8378 {
8379   return SetWithinGenBankSet (data, BioseqseqSet_class_pop_set);
8380 }
8381 
PhyWithinGenBankSet(Pointer data)8382 static Int2 LIBCALLBACK PhyWithinGenBankSet (Pointer data)
8383 
8384 {
8385   return SetWithinGenBankSet (data, BioseqseqSet_class_phy_set);
8386 }
8387 
RemoveExtraneousSets(Pointer data)8388 extern Int2 LIBCALLBACK RemoveExtraneousSets (Pointer data)
8389 
8390 {
8391   BioseqPtr         bsp;
8392   BioseqSetPtr      bssp;
8393   Uint1             _class;
8394   ValNodePtr        descr1 = NULL;
8395   ValNodePtr        descr2 = NULL;
8396   BioseqSetPtr      first = NULL;
8397   ObjMgrDataPtr     omdptop;
8398   ObjMgrData        omdata;
8399   OMProcControlPtr  ompcp;
8400   Uint2             parenttype;
8401   Pointer           parentptr;
8402   SeqEntryPtr       sep;
8403   SeqEntryPtr       tmp;
8404 
8405   ompcp = (OMProcControlPtr) data;
8406   if (ompcp == NULL) return OM_MSG_RET_ERROR;
8407   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
8408   if (sep != NULL && IS_Bioseq_set (sep)) {
8409     bssp = (BioseqSetPtr) sep->data.ptrvalue;
8410     if (bssp != NULL && bssp->_class == 7) {
8411       descr1 = bssp->descr;
8412       bssp->descr = NULL;
8413       _class = 0;
8414       for (tmp = bssp->seq_set; tmp != NULL; tmp = tmp->next) {
8415         if (IS_Bioseq (tmp)) return OM_MSG_RET_DONE;
8416         if (_class == 0 && IS_Bioseq_set (tmp)) {
8417           first = (BioseqSetPtr) tmp->data.ptrvalue;
8418           if (first != NULL) {
8419             _class = first->_class;
8420           }
8421         }
8422       }
8423       if (first != NULL && bssp->seq_set != NULL && bssp->seq_set->next == NULL) {
8424         descr2 = first->descr;
8425         first->descr = NULL;
8426       }
8427       SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
8428       GetSeqEntryParent (sep, &parentptr, &parenttype);
8429       if (_class >= 13 && _class <= 15) {
8430         for (tmp = bssp->seq_set; tmp != NULL; tmp = tmp->next) {
8431           RemovePopPhyMutSet (tmp, FALSE, FALSE);
8432         }
8433         InsetNewSet (bssp, _class);
8434       }
8435       if (_class == 7) {
8436         tmp = bssp->seq_set;
8437         if (tmp != NULL && IS_Bioseq_set (tmp)) {
8438           RemovePopPhyMutSet (tmp, TRUE, FALSE);
8439         }
8440       }
8441       if (IS_Bioseq (sep)) {
8442         bsp = (BioseqPtr) sep->data.ptrvalue;
8443         ValNodeLink (&(bsp->descr), descr1);
8444         ValNodeLink (&(bsp->descr), descr2);
8445       } else if (IS_Bioseq_set (sep)) {
8446         bssp = (BioseqSetPtr) sep->data.ptrvalue;
8447         ValNodeLink (&(bssp->descr), descr1);
8448         ValNodeLink (&(bssp->descr), descr2);
8449       }
8450       SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
8451       RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
8452       ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
8453       ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
8454     }
8455   }
8456   return OM_MSG_RET_DONE;
8457 }
8458 
RepairMessedUpRecord(Pointer data)8459 static Int2 LIBCALLBACK RepairMessedUpRecord (Pointer data)
8460 
8461 {
8462   BioseqSetPtr      bssp;
8463   SeqEntryPtr       last;
8464   SeqEntryPtr       next;
8465   ObjMgrDataPtr     omdptop;
8466   ObjMgrData        omdata;
8467   OMProcControlPtr  ompcp;
8468   Uint2             parenttype;
8469   Pointer           parentptr;
8470   SeqEntryPtr       sep;
8471   SeqEntryPtr       tmp;
8472 
8473   ompcp = (OMProcControlPtr) data;
8474   if (ompcp == NULL) return OM_MSG_RET_ERROR;
8475   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
8476   if (sep == NULL) return OM_MSG_RET_ERROR;
8477   if (! IS_Bioseq_set (sep)) return OM_MSG_RET_ERROR;
8478   bssp = (BioseqSetPtr) sep->data.ptrvalue;
8479   if (bssp == NULL || bssp->_class != 7) return OM_MSG_RET_ERROR;
8480   SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
8481   GetSeqEntryParent (sep, &parentptr, &parenttype);
8482   tmp = bssp->seq_set;
8483   while (tmp != NULL) {
8484     next = tmp->next;
8485     tmp->next = NULL;
8486     if (IS_Bioseq_set (tmp)) {
8487       RemovePopPhyMutSet (tmp, FALSE, TRUE);
8488     }
8489     last = bssp->seq_set;
8490     while (last->next != NULL) {
8491       last = last->next;
8492     }
8493     last->next = next;
8494     tmp = next;
8495   }
8496   SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
8497   RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
8498   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
8499   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
8500   return OM_MSG_RET_DONE;
8501 }
8502 
8503 
MakeGeneXref(SeqFeatPtr sfpr,SeqFeatPtr sfpg)8504 static void MakeGeneXref (SeqFeatPtr sfpr, SeqFeatPtr sfpg)
8505 
8506 {
8507   SeqFeatXrefPtr  curr;
8508   GeneRefPtr      grp;
8509   SeqFeatXrefPtr  PNTR last;
8510   CharPtr         locus;
8511   SeqFeatXrefPtr  next;
8512   SeqFeatXrefPtr  xref;
8513 
8514   if (sfpr == NULL || sfpg == NULL || sfpg->data.choice != SEQFEAT_GENE) return;
8515   grp = (GeneRefPtr) sfpg->data.value.ptrvalue;
8516   if (grp == NULL) return;
8517   locus = grp->locus;
8518   if (StringHasNoText (locus)) return;
8519   last = (SeqFeatXrefPtr PNTR) &(sfpr->xref);
8520   curr = sfpr->xref;
8521   while (curr != NULL) {
8522     next = curr->next;
8523     if (curr->data.choice == SEQFEAT_GENE) {
8524       *last = next;
8525       curr->next = NULL;
8526       SeqFeatXrefFree (curr);
8527     } else {
8528       last = &(curr->next);
8529     }
8530     curr = next;
8531   }
8532   grp = GeneRefNew ();
8533   if (grp == NULL) return;
8534   grp->locus = StringSave (locus);
8535   TrimSpacesAroundString (grp->locus);
8536   xref = SeqFeatXrefNew ();
8537   sfpr->xref = xref;
8538   if (xref != NULL) {
8539     xref->data.choice = SEQFEAT_GENE;
8540     xref->data.value.ptrvalue = (Pointer) grp;
8541   }
8542 }
8543 
GetSeqs(BioseqPtr bsp,SeqMgrBioseqContextPtr context)8544 static Boolean LIBCALLBACK GetSeqs (BioseqPtr bsp, SeqMgrBioseqContextPtr context)
8545 
8546 {
8547   FILE  *fp;
8548   Char  str [256];
8549 
8550   fp = (FILE *) context->userdata;
8551   if (BioseqLabel (bsp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8552     fprintf (fp, "  Bioseq item %d %s\n", (int) context->itemID, str);
8553   }
8554   return TRUE;
8555 }
8556 
GetSegs(SeqLocPtr slp,SeqMgrSegmentContextPtr context)8557 static Boolean LIBCALLBACK GetSegs (SeqLocPtr slp, SeqMgrSegmentContextPtr context)
8558 
8559 {
8560   FILE  *fp;
8561   Char  str [256];
8562 
8563   fp = (FILE *) context->userdata;
8564   if (SeqLocLabel (slp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8565     fprintf (fp, "  SeqLoc item %d %s cumulative %ld\n", (int) context->itemID,
8566              str, (long) context->cumOffset);
8567   }
8568   return TRUE;
8569 }
8570 
GetDescs(ValNodePtr sdp,SeqMgrDescContextPtr context)8571 static Boolean LIBCALLBACK GetDescs (ValNodePtr sdp, SeqMgrDescContextPtr context)
8572 
8573 {
8574   FILE  *fp;
8575   Char  str [256];
8576 
8577   fp = (FILE *) context->userdata;
8578   if (SeqDescLabel (sdp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8579     fprintf (fp, "  Descriptor item %d index %d %s\n",
8580             (int) context->itemID, (int) context->index, str);
8581   }
8582   return TRUE;
8583 }
8584 
GetFeats(SeqFeatPtr sfp,SeqMgrFeatContextPtr context)8585 static Boolean LIBCALLBACK GetFeats (SeqFeatPtr sfp, SeqMgrFeatContextPtr context)
8586 
8587 {
8588   FILE  *fp;
8589   Char  str [256];
8590 
8591   fp = (FILE *) context->userdata;
8592   if (FeatDefLabel (sfp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8593     fprintf (fp, "  Feature item %d index %d %s\n",
8594              (int) context->itemID, (int) context->index, str);
8595   }
8596   return TRUE;
8597 }
8598 
DoBioseqReport(SeqEntryPtr sep,Pointer mydata,Int4 index,Int2 indent)8599 static void DoBioseqReport (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
8600 
8601 {
8602   BioseqPtr          bsp;
8603   SeqMgrDescContext  desccontext;
8604   SeqMgrFeatContext  featcontext;
8605   FILE               *fp;
8606   SeqFeatPtr         gene;
8607   Int2               i;
8608   Int4Ptr            ivals;
8609   Int2               numivals;
8610   ValNodePtr         sdp;
8611   SeqFeatPtr         sfp;
8612   Char               str [256];
8613 
8614   if (sep == NULL) return;
8615   if (! IS_Bioseq (sep)) return;
8616   bsp = (BioseqPtr) sep->data.ptrvalue;
8617   if (bsp == NULL) return;
8618 
8619   fp = (FILE*) mydata;
8620   if (fp == NULL) return;
8621 
8622   if (BioseqLabel (bsp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8623     fprintf (fp, "Bioseq %s\n\n", str);
8624   }
8625 
8626   if (bsp->repr == Seq_repr_seg) {
8627     fprintf (fp, " Exploring segments\n\n");
8628     SeqMgrExploreSegments (bsp, (Pointer) fp, GetSegs);
8629     fprintf (fp, "\n");
8630   }
8631 
8632   if (ISA_aa (bsp->mol)) {
8633     sfp = SeqMgrGetBestProteinFeature (bsp, NULL);
8634     if (FeatDefLabel (sfp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8635       fprintf (fp, "  Best protein %s", str);
8636     }
8637     sfp = SeqMgrGetCDSgivenProduct (bsp, NULL);
8638     if (FeatDefLabel (sfp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8639       fprintf (fp, ", best cds %s", str);
8640     }
8641     fprintf (fp, "\n\n");
8642   }
8643 
8644 
8645   fprintf (fp, " Exploring descriptors\n\n");
8646   SeqMgrExploreDescriptors (bsp, (Pointer) fp, GetDescs, NULL);
8647   fprintf (fp, "\n");
8648 
8649   fprintf (fp, " Exploring features\n\n");
8650   SeqMgrExploreFeatures (bsp, (Pointer) fp, GetFeats, NULL, NULL, NULL);
8651   fprintf (fp, "\n");
8652 
8653 
8654   fprintf (fp, " Collecting descriptors\n\n");
8655   sdp = SeqMgrGetNextDescriptor (bsp, NULL, 0, &desccontext);
8656   while (sdp != NULL) {
8657     if (SeqDescLabel (sdp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8658       fprintf (fp, "  Descriptor item %d index %d %s\n",
8659                (int) desccontext.itemID, (int) desccontext.index, str);
8660     }
8661     sdp = SeqMgrGetNextDescriptor (bsp, sdp, 0, &desccontext);
8662   }
8663   fprintf (fp, "\n");
8664 
8665   fprintf (fp, " Collecting features\n\n");
8666   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &featcontext);
8667   while (sfp != NULL) {
8668     if (FeatDefLabel (sfp, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8669       fprintf (fp, "  Feature item %d index %d %s",
8670                (int) featcontext.itemID, (int) featcontext.index, str);
8671     }
8672     if (featcontext.seqfeattype != SEQFEAT_GENE) {
8673       gene = SeqMgrGetOverlappingGene (sfp->location, NULL);
8674       if (gene != NULL) {
8675         if (FeatDefLabel (gene, str, sizeof (str) - 1, OM_LABEL_BOTH)) {
8676           fprintf (fp, ", gene %s", str);
8677         }
8678       }
8679     }
8680     fprintf (fp, "\n");
8681     ivals = featcontext.ivals;
8682     numivals = featcontext.numivals * 2;
8683     if (ivals != NULL && numivals > 0) {
8684       fprintf (fp, "    (");
8685       for (i = 0; i < numivals; i += 2) {
8686         if (i > 0) {
8687           fprintf (fp, ", ");
8688         }
8689         fprintf (fp, "%ld-%ld", (long) ivals [i], (long) ivals [i + 1]);
8690       }
8691       fprintf (fp, ")\n");
8692     }
8693     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &featcontext);
8694   }
8695   fprintf (fp, "\n");
8696 }
8697 
DoBioseqIndexing(Pointer data)8698 static Int2 LIBCALLBACK DoBioseqIndexing (Pointer data)
8699 
8700 {
8701   BioseqPtr         bsp = NULL;
8702   Uint2             entityID;
8703   FILE              *fp;
8704   OMProcControlPtr  ompcp;
8705   Char              path [PATH_MAX];
8706   SeqEntryPtr       sep;
8707   SeqFeatPtr        sfp = NULL;
8708 
8709   ompcp = (OMProcControlPtr) data;
8710   if (ompcp == NULL || ompcp->input_entityID == 0) {
8711     Message (MSG_ERROR, "Please select a Bioseq");
8712     return OM_MSG_RET_ERROR;
8713   }
8714   switch (ompcp->input_itemtype) {
8715     case OBJ_BIOSEQ :
8716       bsp = (BioseqPtr) ompcp->input_data;
8717       break;
8718     case OBJ_SEQFEAT:
8719       sfp = (SeqFeatPtr) ompcp->input_data;
8720       break;
8721     case 0 :
8722       return OM_MSG_RET_ERROR;
8723     default :
8724       return OM_MSG_RET_ERROR;
8725   }
8726   if (sfp != NULL) {
8727     bsp = BioseqFindFromSeqLoc (sfp->location);
8728   }
8729   if (bsp == NULL) {
8730     Message (MSG_ERROR, "Please select a Bioseq");
8731     return OM_MSG_RET_ERROR;
8732   }
8733   entityID = SeqMgrIndexFeatures (ompcp->input_entityID, NULL);
8734   if (entityID == 0) {
8735     Message (MSG_ERROR, "SeqMgrReindexBioseqExtraData failed");
8736     return OM_MSG_RET_ERROR;
8737   }
8738   sep = GetTopSeqEntryForEntityID (entityID);
8739   if (sep == NULL) return OM_MSG_RET_DONE;
8740   TmpNam (path);
8741   fp = FileOpen (path, "w");
8742 
8743   if (sfp != NULL) {
8744 
8745     fprintf (fp, " Exploring features filtered by location\n\n");
8746     SeqMgrExploreFeatures (bsp, (Pointer) fp, GetFeats, sfp->location, NULL, NULL);
8747     fprintf (fp, "\n");
8748 
8749   } else {
8750 
8751     fprintf (fp, "Exploring bioseqs\n\n");
8752     SeqMgrExploreBioseqs (entityID, 0, (Pointer) fp, GetSeqs, TRUE, TRUE, TRUE);
8753     fprintf (fp, "\n");
8754 
8755     SeqEntryExplore (sep, (Pointer) fp, DoBioseqReport);
8756   }
8757   FileClose (fp);
8758   LaunchGeneralTextViewer (path, "Bioseq Index Report");
8759   FileRemove (path);
8760   return OM_MSG_RET_DONE;
8761 }
8762 
FindNonACGT(Pointer data)8763 static Int2 LIBCALLBACK FindNonACGT (Pointer data)
8764 
8765 {
8766   Byte              bases [400];
8767   BioseqPtr         bsp = NULL;
8768   Uint1             code = Seq_code_iupacna;
8769   Int2              ctr;
8770   FILE              *fp;
8771   Int2              i;
8772   Boolean           is_bad = FALSE;
8773   Int4              len;
8774   OMProcControlPtr  ompcp;
8775   Char              path [PATH_MAX];
8776   Uint1             residue;
8777   SeqPortPtr        spp = NULL;
8778   Int4              total = 0;
8779 
8780   ompcp = (OMProcControlPtr) data;
8781   if (ompcp == NULL || ompcp->input_entityID == 0) {
8782     Message (MSG_ERROR, "Please select a Bioseq");
8783     return OM_MSG_RET_ERROR;
8784   }
8785   switch (ompcp->input_itemtype) {
8786     case OBJ_BIOSEQ :
8787       bsp = (BioseqPtr) ompcp->input_data;
8788       break;
8789     default :
8790       break;
8791   }
8792   if (bsp == NULL) {
8793     Message (MSG_ERROR, "Please select a Bioseq");
8794     return OM_MSG_RET_ERROR;
8795   }
8796   if (ISA_aa (bsp->mol)) {
8797     code = Seq_code_ncbieaa;
8798   }
8799 
8800   spp = SeqPortNew (bsp, 0, -1, 0, code);
8801   len = bsp->length;
8802 
8803   if (spp == NULL) return OM_MSG_RET_ERROR;
8804 
8805   TmpNam (path);
8806   fp = FileOpen (path, "w");
8807 
8808   /* use SeqPortRead rather than SeqPortGetResidue for faster performance */
8809 
8810   ctr = SeqPortRead (spp, bases, sizeof (bases));
8811   i = 0;
8812   residue = (Uint1) bases [i];
8813   while (residue != SEQPORT_EOF) {
8814     if (IS_residue (residue)) {
8815       total++;
8816       switch (residue) {
8817         case 'A' :
8818         case 'C' :
8819         case 'G' :
8820         case 'T' :
8821           break;
8822         default :
8823           fprintf (fp, "Bad residue '%c' at position %ld\n", (char) residue, (long) total);
8824           is_bad = TRUE;
8825           break;
8826       }
8827     }
8828     i++;
8829     if (i >= ctr) {
8830       i = 0;
8831       ctr = SeqPortRead (spp, bases, sizeof (bases));
8832       if (ctr < 0) {
8833         bases [0] = -ctr;
8834       } else if (ctr < 1) {
8835         bases [0] = SEQPORT_EOF;
8836       }
8837     }
8838     residue = (Uint1) bases [i];
8839   }
8840 
8841   SeqPortFree (spp);
8842 
8843   if (! is_bad) {
8844     fprintf (fp, "No ambiguous residues found");
8845   }
8846 
8847   FileClose (fp);
8848   LaunchGeneralTextViewer (path, "Bioseq Index Report");
8849   FileRemove (path);
8850   return OM_MSG_RET_DONE;
8851 }
8852 
RevStringUpper(CharPtr str)8853 static void NEAR RevStringUpper (CharPtr str)
8854 {
8855 	CharPtr nd;
8856 	Char tmp;
8857 
8858 		if (str == NULL)
8859 			return;
8860     nd = str;
8861 	while (*nd != '\0')
8862 		nd++;
8863 	nd--;
8864 
8865 	while (nd > str)
8866 	{
8867 		tmp = TO_UPPER(*nd);
8868 		*nd = TO_UPPER(*str);
8869 		*str = tmp;
8870 		nd--; str++;
8871 	}
8872 
8873 	if (nd == str)
8874 		*nd = TO_UPPER(*nd);
8875 	return;
8876 }
8877 
8878 
ReindexBioseqs(BioseqPtr bsp,Pointer userdata)8879 static void ReindexBioseqs (BioseqPtr bsp, Pointer userdata)
8880 
8881 {
8882   SeqMgrReplaceInBioseqIndex (bsp);
8883 }
8884 
DoClearSeqEntryScope(Pointer data)8885 static Int2 LIBCALLBACK DoClearSeqEntryScope (Pointer data)
8886 
8887 {
8888   OMProcControlPtr  ompcp;
8889   SeqEntryPtr       sep;
8890 
8891   SeqEntrySetScope (NULL);
8892   ompcp = (OMProcControlPtr) data;
8893   if (ompcp != NULL) {
8894     sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
8895     if (sep != NULL) {
8896       VisitBioseqsInSep (sep, NULL, ReindexBioseqs);
8897     }
8898   }
8899   SeqEntrySetScope (NULL);
8900   return OM_MSG_RET_DONE;
8901 }
8902 
SetupSequinFilters(void)8903 extern void SetupSequinFilters (void)
8904 
8905 {
8906   Char  str [32];
8907 
8908   if (indexerVersion) {
8909     REGISTER_CLEAR_SEQENTRYSCOPE;
8910     REGISTER_AUTHORIZEDACCESSUSER_DESC_EDIT;
8911     REGISTER_GENOMEPROJSDBUSER_DESC_EDIT;
8912     REGISTER_UNVERIFIED_DESC_EDIT;
8913     REGISTER_DBLINKUSER_DESC_EDIT;
8914     REGISTER_REFGENEUSER_DESC_EDIT;
8915     REGISTER_COPY_MASTER_SOURCE_TO_SEGMENTS;
8916     REGISTER_DESCRIPTOR_PROPAGATE;
8917   }
8918 
8919   if (GetAppParam ("SEQUIN", "SETTINGS", "ALLOWDETACH",
8920                     NULL, str, sizeof (str)) &&
8921                     StringICmp (str, "TRUE") == 0) {
8922     REGISTER_DETACH;
8923   }
8924 
8925   REGISTER_STRUCTUREDCOMMENTUSER_DESC_EDIT;
8926   REGISTER_TPAASSEMBLYUSER_DESC_EDIT;
8927 
8928   REGISTER_BIOSEQ_COMPLEMENT;
8929   REGISTER_BIOSEQ_REVERSE;
8930   REGISTER_BIOSEQ_REVCOMP_WITHFEAT;
8931   REGISTER_BIOSEQ_REVCOMP_NOTFEAT;
8932   REGISTER_BIOSEQ_REVCOMP_BYID;
8933 
8934 #if defined(OS_UNIX) || defined(OS_MSWIN)
8935   if (indexerVersion) {
8936     REGISTER_CORRECTRNASTRAND;
8937     REGISTER_CORRECTRNASTRANDSMART;
8938   }
8939 #endif
8940 
8941   REGISTER_BIOSEQ_ORF;
8942 
8943   REGISTER_FIX_ALIGNMENT_GAP_GAPS;
8944   REGISTER_FIX_ALIGNMENT_OVER_GAPS;
8945   REGISTER_UPDATE_SEQALIGN;
8946   REGISTER_MAKESEQALIGNMASTERNEWBLAST;
8947   REGISTER_MAKESEQALIGNNEWBLAST;
8948   REGISTER_MAKESEQALIGNPNEWBLAST;
8949   REGISTER_NORMSEQALIGN;
8950   REGISTER_NOMORESEGGAP;
8951   REGISTER_OPENALED;
8952   REGISTER_OPENALED2;
8953 
8954   if (extraServices) {
8955     REGISTER_INTERVAL_COMBINE_AND_FUSE;
8956     REGISTER_INTERVAL_COMBINE;
8957     REGISTER_REPACKAGE_PARTS;
8958     REGISTER_APPLY_SET_TYPE;
8959     REGISTER_REMOVESET;
8960     REGISTER_REMOVESETSINSET;
8961     REGISTER_UNDOSEGSET;
8962     REGISTER_SEGSETREMOVESETSINSET;
8963     REGISTER_ADJUSTMULTISEGSEQ;
8964     REGISTER_UPDATESEGSET;
8965     REGISTER_NEWUPDATESEGSET;
8966     REGISTER_CREATESEGSET;
8967   }
8968 
8969   if (indexerVersion) {
8970     /*
8971     REGISTER_FEAT_INTERVALS_TO_DELTA;
8972     */
8973     REGISTER_REORDER_BY_ID;
8974     REGISTER_SEQUESTER_SETS;
8975     REGISTER_SEGREGATE_BY_FIELD;
8976     REGISTER_FIND_NON_ACGT;
8977     REGISTER_BSP_INDEX;
8978     REGISTER_POPSET_WITHIN_GENBANK;
8979     REGISTER_PHYSET_WITHIN_GENBANK;
8980     REGISTER_NORMALIZE_NUCPROT;
8981     REGISTER_REMOVE_EXTRANEOUS;
8982     REGISTER_REMOVE_MESSEDUP;
8983     REGISTER_GROUP_EXPLODE;
8984     REGISTER_DESKTOP_REPORT;
8985   }
8986 
8987 }
8988 
8989 
8990 /* resolve existing colliding ids section */
8991 
8992 
8993 extern Int2 DoOneSegFixup (SeqEntryPtr sep, Boolean ask);
8994 
8995 typedef struct reconstructsegsetans
8996 {
8997   WindoW  w;
8998   Boolean ans;
8999   Boolean done;
9000 } ReconstructSegSetAnsData, PNTR ReconstructSegSetAnsPtr;
9001 
ReconstructSegSetYes(ButtoN b)9002 static void ReconstructSegSetYes (ButtoN b)
9003 {
9004   ReconstructSegSetAnsPtr rp;
9005 
9006   rp = (ReconstructSegSetAnsPtr) GetObjectExtra (b);
9007   if (rp == NULL) return;
9008   rp->ans = TRUE;
9009 
9010   Remove (rp->w);
9011   rp->done = TRUE;
9012 }
9013 
ReconstructSegSetNo(ButtoN b)9014 static void ReconstructSegSetNo (ButtoN b)
9015 {
9016   ReconstructSegSetAnsPtr rp;
9017 
9018   rp = (ReconstructSegSetAnsPtr) GetObjectExtra (b);
9019   if (rp == NULL) return;
9020   rp->ans = FALSE;
9021 
9022   Remove (rp->w);
9023   rp->done = TRUE;
9024 }
9025 
GetReconstructSegSetAnswer(void)9026 static Boolean GetReconstructSegSetAnswer (void)
9027 {
9028   ReconstructSegSetAnsData rd;
9029   GrouP                    g, h, c;
9030   ButtoN                   b;
9031 
9032   rd.w = ModalWindow(-20, -13, -10, -10, NULL);
9033   h = HiddenGroup(rd.w, -1, 0, NULL);
9034   SetGroupSpacing (h, 10, 10);
9035   rd.done = FALSE;
9036   g= HiddenGroup (h, 1, 0, NULL);
9037   StaticPrompt (g, "Do you wish to also reconstruct segmented bioseqs?", 0, popupMenuHeight, programFont, 'l');
9038   c = HiddenGroup (h, 2, 0, NULL);
9039   b = PushButton(c, "Yes", ReconstructSegSetYes);
9040   SetObjectExtra (b, &rd, NULL);
9041   b = DefaultButton(c, "No", ReconstructSegSetNo);
9042   SetObjectExtra (b, &rd, NULL);
9043   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
9044 
9045   Show(rd.w);
9046   Select (rd.w);
9047   rd.done = FALSE;
9048   while (!rd.done)
9049   {
9050     ProcessExternalEvent ();
9051     Update ();
9052   }
9053   ProcessAnEvent ();
9054   return rd.ans;
9055 }
9056 
9057 
SeqEntryHasSegSets(SeqEntryPtr sep)9058 static Boolean SeqEntryHasSegSets (SeqEntryPtr sep)
9059 {
9060   BioseqSetPtr bssp;
9061   SeqEntryPtr  seq_set;
9062 
9063   if (sep == NULL || !IS_Bioseq_set (sep) || sep->data.ptrvalue == NULL)
9064   {
9065     return FALSE;
9066   }
9067 
9068   bssp = (BioseqSetPtr) sep->data.ptrvalue;
9069 
9070   if (bssp->_class == BioseqseqSet_class_segset)
9071   {
9072     return TRUE;
9073   }
9074   for (seq_set = bssp->seq_set; seq_set != NULL; seq_set = seq_set->next)
9075   {
9076     if (SeqEntryHasSegSets (seq_set))
9077     {
9078       return TRUE;
9079     }
9080   }
9081   return FALSE;
9082 }
9083 
ResolveExistingLocalIDsBaseForm(BaseFormPtr bfp)9084 static void ResolveExistingLocalIDsBaseForm (BaseFormPtr bfp)
9085 
9086 {
9087   Boolean       doParts = FALSE, has_segsets = FALSE;
9088   LclIdListPtr  head = NULL;
9089   SeqEntryPtr   sep, oldscope;
9090 
9091   if (bfp == NULL) return;
9092   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
9093   if (sep == NULL) return;
9094 
9095   /* first, promote local IDs in alignments (if possible) */
9096   oldscope = SeqEntrySetScope (sep);
9097   VisitAnnotsInSep (sep, NULL, PromoteAlignIDsProc);
9098   SeqEntrySetScope (oldscope);
9099 
9100   if (HasAlignmentsWithLocalIDs (sep))
9101   {
9102     if (ANS_CANCEL == Message (MSG_OKC, "This record has alignments with local IDs.  You will need to repair the alignments manually if you resolve colliding IDs.  Do you want to continue?"))
9103     {
9104       return;
9105     }
9106   }
9107   has_segsets = SeqEntryHasSegSets (sep);
9108   if (has_segsets)
9109   {
9110     doParts = GetReconstructSegSetAnswer();
9111   }
9112   SeqEntryExplore (sep, (Pointer) &head, ResolveExistingIDsCallback);
9113   FreeLclTree (&head);
9114   if (doParts) {
9115     DoOneSegFixup (sep, FALSE);
9116   }
9117   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9118   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9119 }
9120 
9121 extern void ResolveExistingLocalIDs (IteM i);
ResolveExistingLocalIDs(IteM i)9122 extern void ResolveExistingLocalIDs (IteM i)
9123 {
9124   BaseFormPtr   bfp;
9125 
9126 #ifdef WIN_MAC
9127   bfp = currentFormDataPtr;
9128 #else
9129   bfp = GetObjectExtra (i);
9130 #endif
9131 
9132   if (bfp == NULL) return;
9133   ResolveExistingLocalIDsBaseForm (bfp);
9134 }
9135 
ResolveExistingLocalIDsToolBtn(ButtoN b)9136 extern void ResolveExistingLocalIDsToolBtn (ButtoN b)
9137 {
9138   BaseFormPtr   bfp;
9139 
9140   bfp = (BaseFormPtr) GetObjectExtra (b);
9141   if (bfp == NULL) return;
9142   ResolveExistingLocalIDsBaseForm (bfp);
9143 }
9144 
9145 extern void SetSourceFocus (IteM i);
9146 extern void ClearSourceFocus (IteM i);
9147 
SetDescriptorFocus(BioseqPtr bsp,SeqMgrBioseqContextPtr bContext)9148 static Boolean LIBCALLBACK SetDescriptorFocus (BioseqPtr bsp,
9149 					SeqMgrBioseqContextPtr bContext)
9150 {
9151   SeqMgrFeatContext fContext;
9152   SeqMgrDescContext dContext;
9153   BioSourcePtr      biop;
9154   Boolean           is_focus;
9155   SeqDescrPtr       sdp;
9156 
9157   /* Only set the focus when the Bioseq has */
9158   /* a source feature in addition to the    */
9159   /* source descriptor.                     */
9160 
9161   is_focus = (Boolean) * ((BoolPtr) bContext->userdata);
9162 
9163   /* don't need feature to clear existing focus on descriptor */
9164 
9165   if (is_focus && NULL == SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_BIOSRC, 0,
9166 				    &fContext))
9167     return TRUE;
9168 
9169   /* Set the focus on all of the Bioseq's */
9170   /* source descriptors.                  */
9171 
9172   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dContext);
9173   while (NULL != sdp) {
9174     biop = (BioSourcePtr) sdp->data.ptrvalue;
9175     if (biop == NULL)
9176       return TRUE;
9177     biop->is_focus = is_focus;
9178     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_source, &dContext);
9179   }
9180 
9181   /* Return true to continue on to next Bioseq */
9182 
9183   return TRUE;
9184 }
9185 
CommonSourceFocus(IteM i,Boolean setfocus)9186 static void CommonSourceFocus (IteM i, Boolean setfocus)
9187 
9188 {
9189   BaseFormPtr   bfp;
9190   Boolean       flag;
9191   SeqEntryPtr   sep;
9192 
9193 #ifdef WIN_MAC
9194   bfp = currentFormDataPtr;
9195 #else
9196   bfp = GetObjectExtra (i);
9197 #endif
9198   if (bfp == NULL) return;
9199   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
9200   if (sep == NULL) return;
9201   flag = setfocus;
9202   SeqMgrExploreBioseqs (0, sep->data.ptrvalue, (Pointer) &flag,
9203 			SetDescriptorFocus, TRUE, TRUE, TRUE);
9204   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9205   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9206 }
9207 
SetSourceFocus(IteM i)9208 extern void SetSourceFocus (IteM i)
9209 
9210 {
9211   CommonSourceFocus (i, TRUE);
9212 }
9213 
ClearSourceFocus(IteM i)9214 extern void ClearSourceFocus (IteM i)
9215 
9216 {
9217   CommonSourceFocus (i, FALSE);
9218 }
9219 
9220 
ConsolidateLikeModifiersProc(BioSourcePtr biop,Pointer userdata)9221 static void ConsolidateLikeModifiersProc (BioSourcePtr biop, Pointer userdata)
9222 {
9223   SubSourcePtr ssp;
9224   OrgModPtr    mod;
9225   Boolean      use_semicolon;
9226 
9227   if (biop == NULL || userdata == NULL) return;
9228 
9229   use_semicolon = *((Boolean PNTR) userdata);
9230 
9231   for (ssp = biop->subtype; ssp != NULL; ssp = ssp->next)
9232   {
9233     if (ssp->name != NULL)
9234     {
9235       ConsolidateOneLikeSubSourceModifier (ssp, use_semicolon);
9236     }
9237   }
9238 
9239   if (biop->org == NULL || biop->org->orgname == NULL) return;
9240   for (mod = biop->org->orgname->mod; mod != NULL; mod = mod->next)
9241   {
9242     if (mod->subname != NULL)
9243     {
9244       ConsolidateOneLikeOrganismModifier (mod, use_semicolon);
9245     }
9246   }
9247 }
9248 
ConsolidateLikeModifiers(IteM i,Boolean use_semicolon)9249 static void ConsolidateLikeModifiers (IteM i, Boolean use_semicolon)
9250 {
9251   BaseFormPtr  bfp;
9252   SeqEntryPtr  sep;
9253 
9254 #ifdef WIN_MAC
9255   bfp = currentFormDataPtr;
9256 #else
9257   bfp = GetObjectExtra (i);
9258 #endif
9259   if (bfp == NULL) return;
9260   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
9261   if (sep == NULL) return;
9262   VisitBioSourcesInSep (sep, &use_semicolon, ConsolidateLikeModifiersProc);
9263   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9264   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9265 }
9266 
ConsolidateLikeModifiersWithSemicolons(IteM i)9267 extern void ConsolidateLikeModifiersWithSemicolons (IteM i)
9268 {
9269   ConsolidateLikeModifiers (i, TRUE);
9270 }
9271 
ConsolidateLikeModifiersWithoutSemicolons(IteM i)9272 extern void ConsolidateLikeModifiersWithoutSemicolons (IteM i)
9273 {
9274   ConsolidateLikeModifiers (i, FALSE);
9275 }
9276 
GetCountry(Uint1 data_choice,Pointer data,Pointer metadata)9277 static Pointer GetCountry (Uint1 data_choice, Pointer data, Pointer metadata)
9278 {
9279   ValNode vn;
9280 
9281   vn.choice = SourceQualChoice_textqual;
9282   vn.data.intvalue = Source_qual_country;
9283   vn.next = NULL;
9284   return GetSourceQualFromBioSource (GetBioSourceFromObject (data_choice, data), &vn, NULL);
9285 }
9286 
9287 
GetAccession(Uint1 data_choice,Pointer data,Pointer metadata)9288 static Pointer GetAccession (Uint1 data_choice, Pointer data, Pointer metadata)
9289 {
9290   ValNode vn;
9291 
9292   vn.choice = data_choice;
9293   vn.data.ptrvalue = data;
9294   vn.next = NULL;
9295   return GetParentLabelForDiscrepancyItem (&vn);
9296 }
9297 
BulkSetCountry(Pointer target,Pointer data)9298 static void BulkSetCountry (Pointer target, Pointer data)
9299 {
9300   ValNode    vn;
9301   SeqDescrPtr sdp = (SeqDescrPtr) target;
9302 
9303   if (sdp == NULL || sdp->choice != Seq_descr_source) return;
9304 
9305   vn.choice = SourceQualChoice_textqual;
9306   vn.data.intvalue = Source_qual_country;
9307   vn.next = NULL;
9308 
9309   SetSourceQualInBioSource (sdp->data.ptrvalue, &vn, NULL, (CharPtr) data, ExistingTextOption_replace_old);
9310 }
9311 
9312 
9313 static BulkEdFieldData country_fields[] = {
9314   { "Country", BulkSetCountry, BulkSetSimpleTextString, GetCountry, BulkDisplaySimpleText, BulkFreeSimpleText, BulkSimpleTextDialog, BulkFormatSimpleText, NULL, NULL, BulkSimpleTextCopy },
9315   { "Accession", NULL, NULL, GetAccession, BulkDisplaySimpleText, BulkFreeSimpleText, NULL, BulkFormatSimpleText, NULL, NULL, BulkSimpleTextCopy },
9316   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
9317 
9318 
CountryLookup(IteM i,Boolean with_cap_fix)9319 static void CountryLookup (IteM i, Boolean with_cap_fix)
9320 {
9321   BaseFormPtr  bfp;
9322   SeqEntryPtr  sep;
9323   ValNodePtr   unfixable = NULL;
9324 
9325 
9326 #ifdef WIN_MAC
9327   bfp = currentFormDataPtr;
9328 #else
9329   bfp = GetObjectExtra (i);
9330 #endif
9331   if (bfp == NULL) return;
9332   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
9333   if (sep == NULL) return;
9334 
9335   unfixable = FixupCountryQuals (sep, with_cap_fix);
9336 
9337   if (unfixable != NULL) {
9338     BulkEditorObjectList (bfp->input_entityID, "Country Modifiers That Could Not Be Autocorrected", unfixable, country_fields);
9339   }
9340 
9341   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9342   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9343 }
9344 
9345 
CountryLookupWithoutCapFix(IteM i)9346 extern void CountryLookupWithoutCapFix (IteM i)
9347 {
9348   CountryLookup (i, FALSE);
9349 }
9350 
9351 
CountryLookupWithCapFix(IteM i)9352 extern void CountryLookupWithCapFix (IteM i)
9353 {
9354   CountryLookup (i, TRUE);
9355 }
9356 
9357 
FixMouseStrains(IteM i)9358 NLM_EXTERN void FixMouseStrains (IteM i)
9359 {
9360   BaseFormPtr  bfp;
9361   SeqEntryPtr  sep;
9362 
9363 #ifdef WIN_MAC
9364   bfp = currentFormDataPtr;
9365 #else
9366   bfp = GetObjectExtra (i);
9367 #endif
9368   if (bfp == NULL) return;
9369   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
9370   if (sep == NULL) return;
9371   if (FixupMouseStrains(sep, NULL)) {
9372     ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9373     ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9374   }
9375 }
9376 
9377 
ConvertPseudoCDSToMiscFeat(IteM i)9378 extern void ConvertPseudoCDSToMiscFeat (IteM i)
9379 {
9380   BaseFormPtr  bfp;
9381 
9382 #ifdef WIN_MAC
9383   bfp = currentFormDataPtr;
9384 #else
9385   bfp = GetObjectExtra (i);
9386 #endif
9387   if (bfp == NULL) return;
9388   ConvertPseudoCDSToMiscFeatsForEntityID (bfp->input_entityID);
9389   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9390   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9391   Update ();
9392 }
9393 
9394 static Boolean
IsParseableInfluenzaAVirusBioSource(BioSourcePtr biop,CharPtr PNTR strain,CharPtr PNTR serotype)9395 IsParseableInfluenzaAVirusBioSource
9396 (BioSourcePtr biop,
9397  CharPtr PNTR strain,
9398  CharPtr PNTR serotype)
9399 {
9400   CharPtr         desired_name = "Influenza A virus";
9401   Int4            desired_len = StringLen (desired_name);
9402   CharPtr         first_paren = NULL, second_paren = NULL;
9403   CharPtr         first_paren_close = NULL, second_paren_close = NULL;
9404   CharPtr         cp;
9405   Int4            strain_len, serotype_len;
9406 
9407   if (biop == NULL || biop->org == NULL || biop->org->taxname == NULL
9408       || strain == NULL
9409       || serotype == NULL)
9410   {
9411     return FALSE;
9412   }
9413 
9414   if (StringNICmp (biop->org->taxname, desired_name, desired_len) != 0)
9415   {
9416     return FALSE;
9417   }
9418 
9419   first_paren = StringChr (biop->org->taxname + desired_len, '(');
9420   if (first_paren == NULL) return FALSE;
9421   cp = first_paren + 1;
9422   while (*cp != ')' && *cp != '(' && *cp != 0)
9423   {
9424     cp++;
9425   }
9426   if (*cp != '(')
9427   {
9428     return FALSE;
9429   }
9430   second_paren = cp;
9431   cp++;
9432   while (*cp != ')' && *cp != '(' && *cp != 0)
9433   {
9434     cp++;
9435   }
9436   if (*cp != ')')
9437   {
9438     return FALSE;
9439   }
9440   second_paren_close = cp;
9441   cp++;
9442   while (*cp != ')' && *cp != '(' && *cp != 0)
9443   {
9444     cp++;
9445   }
9446   if (*cp != ')')
9447   {
9448     return FALSE;
9449   }
9450   first_paren_close = cp;
9451 
9452   strain_len = second_paren - first_paren + first_paren_close - second_paren_close;
9453   serotype_len = second_paren_close - second_paren;
9454   *strain = (CharPtr) MemNew (strain_len * sizeof (Char));
9455   *serotype = (CharPtr) MemNew (serotype_len * sizeof (Char));
9456   if (*strain == NULL || *serotype == NULL)
9457   {
9458     *strain = MemFree (*strain);
9459     *serotype = MemFree (*serotype);
9460     return FALSE;
9461   }
9462   StringNCpy (*strain, first_paren + 1, second_paren - first_paren - 1);
9463   if (first_paren_close - second_paren_close > 1)
9464   {
9465     StringCat (*strain, " ");
9466     StringNCat (*strain, second_paren_close + 1, first_paren_close - second_paren_close - 1);
9467   }
9468   StringNCpy (*serotype, second_paren + 1, second_paren_close - second_paren - 1);
9469 
9470   return TRUE;
9471 }
9472 
ParseInfluenzaAVirusNamesCallback(BioSourcePtr biop,Pointer userdata)9473 static void ParseInfluenzaAVirusNamesCallback (BioSourcePtr biop, Pointer userdata)
9474 {
9475   CharPtr         strain = NULL, serotype = NULL;
9476   OrgModPtr       strain_omp, serotype_omp, last_omp, omp;
9477   Boolean         added_strain = FALSE, added_serotype = FALSE;
9478   ExistingTextPtr etp;
9479 
9480   etp = (ExistingTextPtr) userdata;
9481 
9482   if (!IsParseableInfluenzaAVirusBioSource (biop, &strain, &serotype))
9483   {
9484     return;
9485   }
9486 
9487   if (biop->org->orgname == NULL)
9488   {
9489     biop->org->orgname = OrgNameNew ();
9490     if (biop->org->orgname == NULL)
9491     {
9492       return;
9493     }
9494   }
9495 
9496   last_omp = NULL;
9497   for (omp = biop->org->orgname->mod;
9498        omp != NULL && (!added_strain || ! added_serotype);
9499        omp = omp->next)
9500   {
9501     if (omp->subtype == ORGMOD_strain)
9502     {
9503       omp->subname = HandleExistingText (omp->subname, strain, etp);
9504       added_strain = TRUE;
9505     }
9506     else if (omp->subtype == ORGMOD_serotype)
9507     {
9508       omp->subname = HandleExistingText (omp->subname, serotype, etp);
9509       added_serotype = TRUE;
9510     }
9511     last_omp = omp;
9512   }
9513   if (! added_strain)
9514   {
9515     strain_omp = OrgModNew ();
9516     if (strain_omp != NULL)
9517     {
9518       strain_omp->subtype = ORGMOD_strain;
9519       strain_omp->subname = strain;
9520       if (last_omp == NULL)
9521       {
9522         biop->org->orgname->mod = strain_omp;
9523       }
9524       else
9525       {
9526         last_omp->next = strain_omp;
9527       }
9528       last_omp = strain_omp;
9529     }
9530   }
9531   if (!added_serotype)
9532   {
9533     serotype_omp = OrgModNew ();
9534     if (serotype_omp != NULL)
9535     {
9536       serotype_omp->subtype = ORGMOD_serotype;
9537       serotype_omp->subname = serotype;
9538       if (last_omp == NULL)
9539       {
9540         biop->org->orgname->mod = serotype_omp;
9541       }
9542       else
9543       {
9544         last_omp->next = serotype_omp;
9545       }
9546     }
9547   }
9548 }
9549 
ParseInfluenzaAVirusNamesSample(BioSourcePtr biop,Pointer userdata)9550 static void ParseInfluenzaAVirusNamesSample (BioSourcePtr biop, Pointer userdata)
9551 {
9552   CharPtr      strain = NULL, serotype = NULL;
9553   GetSamplePtr gsp;
9554   OrgModPtr    omp;
9555   Boolean      found_strain = FALSE, found_serotype = FALSE;
9556   CharPtr      overwrite_val;
9557 
9558   if (biop == NULL || biop->org == NULL || biop->org->orgname == NULL || userdata == NULL)
9559   {
9560     return;
9561   }
9562 
9563   gsp = (GetSamplePtr) userdata;
9564 
9565   if (!IsParseableInfluenzaAVirusBioSource (biop, &strain, &serotype))
9566   {
9567     return;
9568   }
9569 
9570   for (omp = biop->org->orgname->mod;
9571        omp != NULL && (!found_strain || !found_serotype);
9572        omp = omp->next)
9573   {
9574     overwrite_val = NULL;
9575     if (omp->subtype == ORGMOD_strain)
9576     {
9577       found_strain = TRUE;
9578       overwrite_val = omp->subname;
9579     }
9580     else if (omp->subtype == ORGMOD_serotype)
9581     {
9582       found_serotype = TRUE;
9583       overwrite_val = omp->subname;
9584     }
9585     if (!StringHasNoText (overwrite_val))
9586     {
9587       gsp->num_found ++;
9588       if (gsp->sample_text == NULL)
9589       {
9590         gsp->sample_text = StringSave (overwrite_val);
9591       }
9592       else if (StringCmp (gsp->sample_text, overwrite_val) != 0)
9593       {
9594         gsp->all_same = FALSE;
9595       }
9596     }
9597   }
9598 
9599   strain = MemFree (strain);
9600   serotype = MemFree (serotype);
9601 }
9602 
ParseInfluenzaAVirusNames(IteM i)9603 extern void ParseInfluenzaAVirusNames (IteM i)
9604 {
9605   BaseFormPtr     bfp;
9606   SeqEntryPtr     sep;
9607   GetSamplePtr    gsp;
9608   ExistingTextPtr etp;
9609 
9610 #ifdef WIN_MAC
9611   bfp = currentFormDataPtr;
9612 #else
9613   bfp = GetObjectExtra (i);
9614 #endif
9615   if (bfp == NULL) return;
9616 
9617   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
9618   if (sep == NULL) return;
9619 
9620   gsp = GetSampleNew ();
9621   VisitBioSourcesInSep (sep, gsp, ParseInfluenzaAVirusNamesSample);
9622   etp = GetExistingTextHandlerInfo (gsp == NULL ? 0 : gsp->num_found, FALSE);
9623   gsp = GetSampleFree (gsp);
9624   if (etp == NULL || etp->existing_text_choice != eExistingTextChoiceCancel)
9625   {
9626     VisitBioSourcesInSep (sep, etp, ParseInfluenzaAVirusNamesCallback);
9627   }
9628   etp = MemFree (etp);
9629   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9630   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9631   Update ();
9632 }
9633 
9634 static void
AddStrainAndSerotypeToInfluenzaAVirusNamesCallback(BioSourcePtr biop,Pointer userdata)9635 AddStrainAndSerotypeToInfluenzaAVirusNamesCallback
9636 (BioSourcePtr biop,
9637  Pointer userdata)
9638 {
9639   CharPtr   strain_str = NULL;
9640   CharPtr   serotype_str = NULL;
9641   OrgModPtr omp;
9642   CharPtr   strain_serotype_str;
9643   Int4      len;
9644   CharPtr   desired_name = "Influenza A virus";
9645   Int4      desired_len = StringLen (desired_name);
9646 
9647 
9648   if (biop == NULL || biop->org == NULL || biop->org->orgname == NULL
9649       || StringNICmp (biop->org->taxname, desired_name, desired_len) != 0)
9650   {
9651     return;
9652   }
9653 
9654   for (omp = biop->org->orgname->mod;
9655        omp != NULL && (strain_str == NULL || serotype_str == NULL);
9656        omp = omp->next)
9657   {
9658     if (omp->subtype == ORGMOD_strain)
9659     {
9660       strain_str = omp->subname;
9661     }
9662     else if (omp->subtype == ORGMOD_serotype)
9663     {
9664       serotype_str = omp->subname;
9665     }
9666   }
9667 
9668   if (strain_str == NULL || serotype_str == NULL) return;
9669 
9670   len = StringLen (strain_str) + StringLen (serotype_str) + 6 + StringLen (biop->org->taxname);
9671   strain_serotype_str = (CharPtr) MemNew (len * sizeof (Char));
9672   if (strain_serotype_str == NULL) return;
9673   sprintf (strain_serotype_str, "(%s(%s))", strain_str, serotype_str);
9674   if (StringStr (biop->org->taxname, strain_serotype_str))
9675   {
9676     MemFree (strain_serotype_str);
9677     return;
9678   }
9679   sprintf (strain_serotype_str, "%s (%s(%s))", biop->org->taxname,
9680            strain_str, serotype_str);
9681   SetTaxNameAndRemoveTaxRef (biop->org, strain_serotype_str);
9682   RemoveOldName(biop->org);
9683 }
9684 
AddStrainAndSerotypeToInfluenzaAVirusNames(IteM i)9685 extern void AddStrainAndSerotypeToInfluenzaAVirusNames (IteM i)
9686 {
9687   BaseFormPtr  bfp;
9688   SeqEntryPtr  sep;
9689 
9690 #ifdef WIN_MAC
9691   bfp = currentFormDataPtr;
9692 #else
9693   bfp = GetObjectExtra (i);
9694 #endif
9695   if (bfp == NULL) return;
9696 
9697   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
9698   if (sep == NULL) return;
9699   VisitBioSourcesInSep (sep, NULL, AddStrainAndSerotypeToInfluenzaAVirusNamesCallback);
9700   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9701   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9702   Update ();
9703 }
9704 
9705 
FixInfluenzaVirusName(CharPtr orig_name)9706 extern CharPtr FixInfluenzaVirusName (CharPtr orig_name)
9707 {
9708   CharPtr   desired_name = "Influenza A virus";
9709   Int4      desired_len = StringLen (desired_name);
9710   CharPtr   new_name = NULL, cp, src_cp, dst_cp;
9711 
9712   if (StringHasNoText(orig_name)
9713       || StringNICmp (orig_name, desired_name, desired_len) != 0)
9714   {
9715     return NULL;
9716   }
9717 
9718   cp = orig_name + desired_len;
9719   if (*cp == 0)
9720   {
9721     return NULL;
9722   }
9723 
9724   /* allow one space and only one space between virus and the strain/serotype */
9725 
9726   if (*cp == '(')
9727   {
9728     new_name = (CharPtr) MemNew (sizeof (Char) * (StringLen (orig_name) + 2));
9729     sprintf (new_name, "%s %s", desired_name, cp);
9730   }
9731   else
9732   {
9733     new_name = StringSave (orig_name);
9734   }
9735 
9736   dst_cp = new_name + desired_len;
9737 
9738   if (*dst_cp != ' ')
9739   {
9740     new_name = MemFree (new_name);
9741     return NULL;
9742   }
9743 
9744   dst_cp++;
9745 
9746   src_cp = dst_cp;
9747   /* skip over spaces */
9748   while (isspace (*src_cp))
9749   {
9750     src_cp++;
9751   }
9752   if (*src_cp != '(')
9753   {
9754     new_name = MemFree (new_name);
9755     return NULL;
9756   }
9757   /* copy first open paren */
9758   *dst_cp = *src_cp;
9759   dst_cp++;
9760   src_cp++;
9761 
9762   /* skip over spaces */
9763   while (*src_cp == ' ' || *src_cp == '\t')
9764   {
9765     src_cp++;
9766   }
9767   /* copy to next open paren */
9768   while (*src_cp != '(' && *src_cp != 0)
9769   {
9770     *dst_cp = *src_cp;
9771     dst_cp++;
9772     src_cp++;
9773   }
9774   if (*src_cp == 0)
9775   {
9776     new_name = MemFree (new_name);
9777     return NULL;
9778   }
9779   /* skip back past spaces */
9780   while (*(dst_cp - 1) == ' ' || *(dst_cp - 1) == '\t')
9781   {
9782     dst_cp --;
9783   }
9784   /* copy to first close paren */
9785   while (*src_cp != ')' && *src_cp != 0)
9786   {
9787     *dst_cp = *src_cp;
9788     dst_cp++;
9789     src_cp++;
9790   }
9791   if (*src_cp == 0)
9792   {
9793     new_name = MemFree (new_name);
9794     return NULL;
9795   }
9796   /* skip back past spaces */
9797   while (*(dst_cp - 1) == ' ' || *(dst_cp - 1) == '\t')
9798   {
9799     dst_cp --;
9800   }
9801   /* copy first close paren */
9802   *dst_cp = *src_cp;
9803   dst_cp++;
9804   src_cp++;
9805     /* skip over spaces */
9806   while (*src_cp == ' ' || *src_cp == '\t')
9807   {
9808     src_cp++;
9809   }
9810   /* copy to second close paren */
9811   while (*src_cp != ')' && *src_cp != 0)
9812   {
9813     *dst_cp = *src_cp;
9814     dst_cp++;
9815     src_cp++;
9816   }
9817   if (*src_cp == 0)
9818   {
9819     new_name = MemFree (new_name);
9820     return NULL;
9821   }
9822   /* skip back past spaces */
9823   while (*(dst_cp - 1) == ' ' || *(dst_cp - 1) == '\t')
9824   {
9825     dst_cp --;
9826   }
9827   /* copy second close paren */
9828   *dst_cp = *src_cp;
9829   dst_cp++;
9830   src_cp++;
9831   while (*src_cp == ' ' || *src_cp == '\t')
9832   {
9833       src_cp++;
9834   }
9835   if (*src_cp != 0)
9836   {
9837     new_name = MemFree (new_name);
9838     return NULL;
9839   }
9840   *dst_cp = 0;
9841   return new_name;
9842 }
9843 
9844 static void
FixupInfluenzaAVirusNamesCallback(BioSourcePtr biop,Pointer userdata)9845 FixupInfluenzaAVirusNamesCallback
9846 (BioSourcePtr biop,
9847  Pointer userdata)
9848 {
9849   CharPtr   new_name;
9850 
9851   if (biop == NULL || biop->org == NULL)
9852   {
9853     return;
9854   }
9855 
9856   new_name = FixInfluenzaVirusName (biop->org->taxname);
9857 
9858   if (new_name != NULL)
9859   {
9860     SetTaxNameAndRemoveTaxRef (biop->org, new_name);
9861     RemoveOldName(biop->org);
9862   }
9863 }
9864 
9865 
FixupInfluenzaAVirusNames(IteM i)9866 extern void FixupInfluenzaAVirusNames(IteM i)
9867 {
9868   BaseFormPtr  bfp;
9869   SeqEntryPtr  sep;
9870 
9871 #ifdef WIN_MAC
9872   bfp = currentFormDataPtr;
9873 #else
9874   bfp = GetObjectExtra (i);
9875 #endif
9876   if (bfp == NULL) return;
9877 
9878   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
9879   if (sep == NULL) return;
9880   VisitBioSourcesInSep (sep, NULL, FixupInfluenzaAVirusNamesCallback);
9881   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
9882   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
9883   Update ();
9884 }
9885 
9886 /* The following code is used for global publication editing. */
9887 /* This section of code is used to create a Publication Constraint */
9888 
PubConstraintClearText(PubConstraintPtr pcp)9889 static void PubConstraintClearText (PubConstraintPtr pcp)
9890 {
9891   if (pcp != NULL)
9892   {
9893     pcp->find_str = MemFree (pcp->find_str);
9894   }
9895 }
9896 
PubConstraintFree(PubConstraintPtr pcp)9897 extern PubConstraintPtr PubConstraintFree (PubConstraintPtr pcp)
9898 {
9899   if (pcp != NULL)
9900   {
9901     pcp->find_str = MemFree (pcp->find_str);
9902     pcp = MemFree (pcp);
9903   }
9904   return pcp;
9905 }
9906 
9907 typedef struct pubfieldchoicedialog
9908 {
9909   DIALOG_MESSAGE_BLOCK
9910   PopuP   main_list;
9911   PopuP   author_list;
9912   PopuP   affiliation_list;
9913   Boolean allow_any;
9914 } PubFieldChoiceDialogData, PNTR PubFieldChoiceDialogPtr;
9915 
9916 enum pubfield_main_choice
9917 {
9918   PUB_MAIN_ANY = 1,
9919   PUB_MAIN_TITLE,
9920   PUB_MAIN_AUTHOR,
9921   PUB_MAIN_AFFILIATION
9922 };
9923 
ENUM_ALIST(edit_pub_author_field_alist)9924 static ENUM_ALIST (edit_pub_author_field_alist)
9925   {"Last Name",        PUB_FIELD_LAST_NAME},
9926   {"First Name",       PUB_FIELD_FIRST_NAME},
9927   {"Consortium",       PUB_FIELD_CONSORTIUM},
9928   {"Middle Initial",   PUB_FIELD_MIDDLE_INITIAL},
9929   {"Suffix",           PUB_FIELD_SUFFIX},
9930 END_ENUM_ALIST
9931 
9932 static ENUM_ALIST (edit_pub_affiliation_field_alist)
9933   {"Department",  PUB_FIELD_DEPARTMENT},
9934   {"Institution", PUB_FIELD_INSTITUTION},
9935   {"Address",     PUB_FIELD_ADDRESS},
9936   {"City",        PUB_FIELD_CITY},
9937   {"State",       PUB_FIELD_STATE},
9938   {"Country",     PUB_FIELD_COUNTRY},
9939   {"Zip Code",    PUB_FIELD_ZIP},
9940 END_ENUM_ALIST
9941 
9942 static void ChangePubFieldMainChoice (PopuP p)
9943 {
9944   PubFieldChoiceDialogPtr dlg;
9945   Int4                    main_choice;
9946 
9947   dlg = (PubFieldChoiceDialogPtr) GetObjectExtra (p);
9948   if (dlg != NULL)
9949   {
9950     Hide (dlg->author_list);
9951     Hide (dlg->affiliation_list);
9952     main_choice = GetValue (dlg->main_list);
9953     if (! dlg->allow_any)
9954     {
9955       main_choice ++;
9956     }
9957     if (main_choice == PUB_MAIN_AUTHOR)
9958     {
9959       Show (dlg->author_list);
9960     }
9961     else if (main_choice == PUB_MAIN_AFFILIATION)
9962     {
9963       Show (dlg->affiliation_list);
9964     }
9965   }
9966 }
9967 
ResetPubFieldChoiceDialog(PubFieldChoiceDialogPtr dlg)9968 static void ResetPubFieldChoiceDialog (PubFieldChoiceDialogPtr dlg)
9969 {
9970   if (dlg != NULL)
9971   {
9972     /* if allow_any, 1 is any, otherwise 1 is title */
9973     SetValue (dlg->main_list, 1);
9974     ChangePubFieldMainChoice (dlg->main_list);
9975   }
9976 }
9977 
PubFieldChoiceToDialog(DialoG d,Pointer userdata)9978 static void PubFieldChoiceToDialog (DialoG d, Pointer userdata)
9979 {
9980   PubFieldChoiceDialogPtr dlg;
9981   Int4Ptr                 pFieldChoice;
9982   Int4                    field_choice;
9983 
9984   dlg = (PubFieldChoiceDialogPtr) GetObjectExtra (d);
9985   if (dlg == NULL)
9986   {
9987     return;
9988   }
9989 
9990   ResetPubFieldChoiceDialog (dlg);
9991 
9992   if (userdata == NULL)
9993   {
9994     return;
9995   }
9996 
9997   pFieldChoice = (Int4Ptr) userdata;
9998   field_choice = *pFieldChoice;
9999   if (field_choice == PUB_FIELD_ANY && ! dlg->allow_any)
10000   {
10001     field_choice = PUB_FIELD_TITLE;
10002   }
10003 
10004   if (field_choice == PUB_FIELD_ANY)
10005   {
10006     SetValue (dlg->main_list, PUB_MAIN_ANY);
10007   }
10008   else if (field_choice == PUB_FIELD_TITLE)
10009   {
10010     if (dlg->allow_any)
10011     {
10012       SetValue (dlg->main_list, PUB_MAIN_TITLE);
10013     }
10014     else
10015     {
10016       SetValue (dlg->main_list, PUB_MAIN_TITLE - 1);
10017     }
10018   }
10019   else if (field_choice >= PUB_FIELD_FIRST_NAME
10020            && field_choice <= PUB_FIELD_CONSORTIUM)
10021   {
10022     if (dlg->allow_any)
10023     {
10024       SetValue (dlg->main_list, PUB_MAIN_AUTHOR);
10025     }
10026     else
10027     {
10028       SetValue (dlg->main_list, PUB_MAIN_AUTHOR - 1);
10029     }
10030     SetEnumPopup (dlg->author_list, edit_pub_author_field_alist, field_choice);
10031   }
10032   else if (field_choice >= PUB_FIELD_INSTITUTION)
10033   {
10034     if (dlg->allow_any)
10035     {
10036       SetValue (dlg->main_list, PUB_MAIN_AFFILIATION);
10037     }
10038     else
10039     {
10040       SetValue (dlg->main_list, PUB_MAIN_AFFILIATION - 1);
10041     }
10042     SetEnumPopup (dlg->affiliation_list, edit_pub_affiliation_field_alist, field_choice);
10043   }
10044 
10045   ChangePubFieldMainChoice (dlg->main_list);
10046 }
10047 
DialogToPubFieldChoice(DialoG d)10048 static Pointer DialogToPubFieldChoice (DialoG d)
10049 {
10050   PubFieldChoiceDialogPtr dlg;
10051   Int4                    main_field_choice;
10052   UIEnum                  val;
10053   Int4Ptr                 retval;
10054 
10055   dlg = (PubFieldChoiceDialogPtr) GetObjectExtra (d);
10056   retval = (Int4Ptr) MemNew (sizeof (Int4));
10057   if (retval == NULL)
10058   {
10059     return NULL;
10060   }
10061   *retval = PUB_FIELD_ANY;
10062   if (dlg == NULL)
10063   {
10064     return retval;
10065   }
10066 
10067   main_field_choice = GetValue (dlg->main_list);
10068   if (!dlg->allow_any)
10069   {
10070     main_field_choice ++;
10071   }
10072 
10073   if (main_field_choice == PUB_MAIN_ANY)
10074   {
10075     *retval = PUB_FIELD_ANY;
10076   }
10077   else if (main_field_choice == PUB_MAIN_TITLE)
10078   {
10079     *retval = PUB_FIELD_TITLE;
10080   }
10081   else if (main_field_choice == PUB_MAIN_AUTHOR)
10082   {
10083     if (GetEnumPopup (dlg->author_list, edit_pub_author_field_alist, &val))
10084     {
10085       *retval = val;
10086     }
10087   }
10088   else if (main_field_choice == PUB_MAIN_AFFILIATION)
10089   {
10090     if (GetEnumPopup (dlg->affiliation_list, edit_pub_affiliation_field_alist, &val))
10091     {
10092       *retval = val;
10093     }
10094   }
10095   return retval;
10096 }
10097 
PubFieldChoiceDialog(GrouP h,Boolean allow_any)10098 static DialoG PubFieldChoiceDialog (GrouP h, Boolean allow_any)
10099 
10100 {
10101   PubFieldChoiceDialogPtr dlg;
10102   GrouP                   p, k1;
10103 
10104   dlg = (PubFieldChoiceDialogPtr) MemNew (sizeof (PubFieldChoiceDialogData));
10105   if (dlg == NULL)
10106   {
10107     return NULL;
10108   }
10109 
10110   p = HiddenGroup (h, 2, 0, NULL);
10111   SetObjectExtra (p, dlg, StdCleanupExtraProc);
10112 
10113   dlg->dialog = (DialoG) p;
10114   dlg->todialog = PubFieldChoiceToDialog;
10115   dlg->fromdialog = DialogToPubFieldChoice;
10116   dlg->dialogmessage = NULL;
10117   dlg->testdialog = NULL;
10118 
10119   dlg->allow_any = allow_any;
10120 
10121   dlg->main_list = PopupList (p, TRUE, ChangePubFieldMainChoice);
10122   SetObjectExtra (dlg->main_list, dlg, NULL);
10123   if (allow_any)
10124   {
10125     PopupItem (dlg->main_list, "Any Pub Field");
10126   }
10127   PopupItem (dlg->main_list, "Title");
10128   PopupItem (dlg->main_list, "Author");
10129   PopupItem (dlg->main_list, "Affiliation");
10130 
10131   k1 = HiddenGroup (p, 0, 0, NULL);
10132   dlg->author_list = PopupList (k1, TRUE, NULL);
10133   InitEnumPopup (dlg->author_list, edit_pub_author_field_alist, NULL);
10134   SetEnumPopup (dlg->author_list, edit_pub_author_field_alist, PUB_FIELD_LAST_NAME);
10135   dlg->affiliation_list = PopupList (k1, TRUE, NULL);
10136   InitEnumPopup (dlg->affiliation_list, edit_pub_affiliation_field_alist, NULL);
10137   SetEnumPopup (dlg->affiliation_list, edit_pub_affiliation_field_alist, PUB_FIELD_DEPARTMENT);
10138 
10139   ChangePubFieldMainChoice (dlg->main_list);
10140   AlignObjects (ALIGN_CENTER, (HANDLE) dlg->author_list,
10141                               (HANDLE) dlg->affiliation_list,
10142                               NULL);
10143   return (DialoG) p;
10144 }
10145 
10146 
ENUM_ALIST(pub_stat_alist)10147 static ENUM_ALIST(pub_stat_alist)
10148   {"Any",                     PUB_STAT_ANY},
10149   {"Published",               PUB_STAT_PUBLISHED},
10150   {"Unpublished",             PUB_STAT_UNPUBLISHED},
10151   {"In Press",                PUB_STAT_INPRESS},
10152   {"Submitter Block",         PUB_STAT_PUBLISHED_SUBMISSION},
10153 END_ENUM_ALIST
10154 
10155 typedef struct pubconstraintdialog
10156 {
10157   DIALOG_MESSAGE_BLOCK
10158   TexT    find_str;
10159   ButtoN  insensitive_to_case;
10160   DialoG  field_for_find;
10161   PopuP   pub_status;
10162 } PubConstraintDialogData, PNTR PubConstraintDialogPtr;
10163 
ResetPubConstraintDialog(PubConstraintDialogPtr pcp)10164 static void ResetPubConstraintDialog (PubConstraintDialogPtr pcp)
10165 {
10166   Int4 field_choice = PUB_FIELD_ANY;
10167 
10168   if (pcp == NULL) return;
10169   SetTitle (pcp->find_str, "");
10170   SetStatus (pcp->insensitive_to_case, FALSE);
10171   PointerToDialog (pcp->field_for_find, &field_choice);
10172   SetEnumPopup (pcp->pub_status, pub_stat_alist, PUB_STAT_ANY);
10173 }
10174 
PubConstraintToDialog(DialoG d,Pointer data)10175 static void PubConstraintToDialog (DialoG d, Pointer data)
10176 
10177 {
10178   PubConstraintDialogPtr dlg;
10179   PubConstraintPtr       pcp;
10180 
10181   dlg = (PubConstraintDialogPtr) GetObjectExtra (d);
10182   if (dlg == NULL)
10183   {
10184     return;
10185   }
10186   pcp = (PubConstraintPtr) data;
10187 
10188   ResetPubConstraintDialog (dlg);
10189   if (pcp != NULL)
10190   {
10191     SetTitle (dlg->find_str, pcp->find_str);
10192     SetStatus (dlg->insensitive_to_case, pcp->insensitive_to_case);
10193     PointerToDialog (dlg->field_for_find,  &(pcp->field_for_find));
10194     SetEnumPopup (dlg->pub_status, pub_stat_alist, pcp->pub_status);
10195   }
10196 }
10197 
DialogToPubConstraint(DialoG d)10198 static Pointer DialogToPubConstraint (DialoG d)
10199 
10200 {
10201   PubConstraintDialogPtr dlg;
10202   PubConstraintPtr       pcp;
10203   UIEnum                 val;
10204   Int4Ptr                retval;
10205 
10206   dlg = (PubConstraintDialogPtr) GetObjectExtra (d);
10207   if (dlg == NULL)
10208   {
10209     return NULL;
10210   }
10211   pcp = (PubConstraintPtr) MemNew (sizeof (PubConstraintData));
10212   if (pcp != NULL)
10213   {
10214     pcp->find_str = JustSaveStringFromText (dlg->find_str);
10215     pcp->insensitive_to_case = GetStatus (dlg->insensitive_to_case);
10216     retval = DialogToPointer (dlg->field_for_find);
10217     if (retval == NULL)
10218     {
10219       pcp->field_for_find = PUB_FIELD_ANY;
10220     }
10221     else
10222     {
10223       pcp->field_for_find = *retval;
10224       retval = MemFree (retval);
10225     }
10226     if (GetEnumPopup (dlg->pub_status, pub_stat_alist, &val))
10227     {
10228       pcp->pub_status = val;
10229     }
10230   }
10231   return pcp;
10232 }
10233 
ClearPubConstraint(ButtoN b)10234 static void ClearPubConstraint (ButtoN b)
10235 {
10236   PubConstraintDialogPtr dlg;
10237 
10238   dlg = (PubConstraintDialogPtr) GetObjectExtra (b);
10239   ResetPubConstraintDialog (dlg);
10240 }
10241 
PubConstraintDialog(GrouP h)10242 extern DialoG PubConstraintDialog (GrouP h)
10243 
10244 {
10245   PubConstraintDialogPtr dlg;
10246   GrouP                  p, k1, k3;
10247   ButtoN                 b;
10248   PrompT                 ppt;
10249 
10250   dlg = (PubConstraintDialogPtr) MemNew (sizeof (PubConstraintDialogData));
10251   if (dlg == NULL)
10252   {
10253     return NULL;
10254   }
10255 
10256   p = NormalGroup (h, -1, 0, "Optional Constraints", programFont, NULL);
10257   SetObjectExtra (p, dlg, StdCleanupExtraProc);
10258 
10259   dlg->dialog = (DialoG) p;
10260   dlg->todialog = PubConstraintToDialog;
10261   dlg->fromdialog = DialogToPubConstraint;
10262   dlg->dialogmessage = NULL;
10263   dlg->testdialog = NULL;
10264 
10265   ppt = StaticPrompt (p, "Change only publications meeting these criteria:", 0,
10266                      dialogTextHeight, programFont, 'c');
10267   k1 = HiddenGroup (p, 5, 0, NULL);
10268   StaticPrompt (k1, "Where", 0, dialogTextHeight, programFont, 'c');
10269   dlg->find_str = DialogText (k1, "", 15, NULL);
10270   StaticPrompt (k1, "occurs in", 0, dialogTextHeight, programFont, 'c');
10271   dlg->field_for_find = PubFieldChoiceDialog (k1, TRUE);
10272   dlg->insensitive_to_case = CheckBox (p, "Ignore case", NULL);
10273   k3 = HiddenGroup (p, 2, 0, NULL);
10274   StaticPrompt (k3, "Publication Status", 0, dialogTextHeight, programFont, 'c');
10275   dlg->pub_status = PopupList (k3, TRUE, NULL);
10276   InitEnumPopup (dlg->pub_status, pub_stat_alist, NULL);
10277   SetEnumPopup (dlg->pub_status, pub_stat_alist, 0);
10278 
10279   b = PushButton (p, "Clear Publication Constraint", ClearPubConstraint);
10280   SetObjectExtra (b, dlg, NULL);
10281 
10282   AlignObjects (ALIGN_CENTER, (HANDLE) ppt,
10283                               (HANDLE) k1,
10284                               (HANDLE) dlg->insensitive_to_case,
10285                               (HANDLE) k3,
10286                               (HANDLE) b,
10287                               NULL);
10288   return (DialoG) p;
10289 }
10290 
10291 /* The following functions are used for getting and setting various types of data
10292  * in publications.
10293  */
GetPubTitleSample(PubPtr the_pub)10294 static CharPtr GetPubTitleSample (PubPtr the_pub)
10295 {
10296   CitGenPtr    cgp;
10297   CitArtPtr    cap;
10298   CitBookPtr   cbp;
10299   CitPatPtr    cpp;
10300   CharPtr      retp = NULL;
10301 
10302   if (the_pub == NULL || the_pub->data.ptrvalue == NULL) return NULL;
10303 
10304   switch (the_pub->choice) {
10305     case PUB_Gen :
10306       cgp = (CitGenPtr) the_pub->data.ptrvalue;
10307       retp = cgp->title;
10308       break;
10309     case PUB_Sub :
10310       break;
10311     case PUB_Article :
10312       cap = (CitArtPtr) the_pub->data.ptrvalue;
10313       if(cap->title != NULL)
10314       {
10315         retp = cap->title->data.ptrvalue;
10316       }
10317       break;
10318     case PUB_Book :
10319     case PUB_Man :
10320       cbp = (CitBookPtr) the_pub->data.ptrvalue;
10321       if(cbp->title != NULL)
10322       {
10323         retp = cbp->title->data.ptrvalue;
10324       }
10325       break;
10326     case PUB_Patent :
10327       cpp = (CitPatPtr) the_pub->data.ptrvalue;
10328       retp = cpp->title;
10329       break;
10330     default :
10331       break;
10332   }
10333   return retp;
10334 }
10335 
SetPubTitle(PubPtr the_pub,CharPtr new_title)10336 static void SetPubTitle (PubPtr the_pub, CharPtr new_title)
10337 {
10338   CitGenPtr    cgp;
10339   CitArtPtr    cap;
10340   CitBookPtr   cbp;
10341   CitPatPtr    cpp;
10342 
10343   if (the_pub == NULL || new_title == NULL) return;
10344 
10345   switch (the_pub->choice) {
10346     case PUB_Gen :
10347       cgp = (CitGenPtr) the_pub->data.ptrvalue;
10348       cgp->title = MemFree (cgp->title);
10349       cgp->title = StringSave (new_title);
10350       break;
10351     case PUB_Sub :
10352       break;
10353     case PUB_Article :
10354       cap = (CitArtPtr) the_pub->data.ptrvalue;
10355       if (cap->title == NULL)
10356       {
10357         cap->title = ValNodeNew (cap->title);
10358         cap->title->choice = 1;
10359       }
10360       if(cap->title != NULL)
10361       {
10362         cap->title->data.ptrvalue = MemFree (cap->title->data.ptrvalue);
10363         cap->title->data.ptrvalue = StringSave (new_title);
10364       }
10365       break;
10366     case PUB_Book :
10367     case PUB_Man :
10368       cbp = (CitBookPtr) the_pub->data.ptrvalue;
10369       if (cbp->title == NULL)
10370       {
10371         cbp->title = ValNodeNew (cbp->title);
10372         cbp->title->choice = 1;
10373       }
10374       if(cbp->title != NULL)
10375       {
10376         cbp->title->data.ptrvalue = MemFree (cbp->title->data.ptrvalue);
10377         cbp->title->data.ptrvalue = StringSave (new_title);
10378       }
10379       break;
10380     case PUB_Patent :
10381       cpp = (CitPatPtr) the_pub->data.ptrvalue;
10382       cpp->title = MemFree (cpp->title);
10383       cpp->title = StringSave (new_title);
10384       break;
10385     default :
10386       break;
10387   }
10388 }
10389 
10390 
SetPubAuthorList(PubPtr the_pub,AuthListPtr alp)10391 static Boolean SetPubAuthorList (PubPtr the_pub, AuthListPtr alp)
10392 {
10393   AffilPtr   old_affil = NULL;
10394   AuthListPtr PNTR old_auth;
10395 
10396   if (the_pub == NULL || the_pub->data.ptrvalue == NULL || alp == NULL)
10397     return FALSE;
10398 
10399   old_auth = GetAuthListForPub (the_pub);
10400   if (old_auth == NULL)
10401   {
10402     return FALSE;
10403   }
10404   if (*old_auth != NULL)
10405   {
10406     old_affil = (*old_auth)->affil;
10407     (*old_auth)->affil = NULL;
10408     (*old_auth) = AuthListFree (*old_auth);
10409   }
10410 
10411   alp->affil = AffilFree (alp->affil);
10412   alp->affil = old_affil;
10413   *old_auth = alp;
10414 
10415   return TRUE;
10416 }
10417 
10418 
GetAuthorField(AuthorPtr ap,Int4 field_for_find)10419 static CharPtr GetAuthorField (AuthorPtr ap, Int4 field_for_find)
10420 {
10421   CharPtr      retp = NULL;
10422   NameStdPtr   pNameStandard;
10423 
10424   if (ap == NULL || field_for_find == PUB_FIELD_ANY) return NULL;
10425 
10426   if (ap->name->choice == 2)
10427   {
10428     pNameStandard = (NameStdPtr) ap->name->data;
10429     if (pNameStandard != NULL)
10430     {
10431       switch (field_for_find)
10432       {
10433         case PUB_FIELD_FIRST_NAME:
10434           retp = pNameStandard->names [1];
10435           break;
10436         case PUB_FIELD_MIDDLE_INITIAL:
10437           retp = pNameStandard->names [4];
10438           if (retp != NULL)
10439           {
10440             retp = StringChr (retp, '.');
10441             if (retp != NULL)
10442             {
10443               retp++;
10444             }
10445           }
10446           break;
10447         case PUB_FIELD_LAST_NAME:
10448           retp = pNameStandard->names [0];
10449           break;
10450         case PUB_FIELD_SUFFIX:
10451           retp = pNameStandard->names [5];
10452           break;
10453       }
10454     }
10455   }
10456   else if (ap->name->choice == 5 && field_for_find == PUB_FIELD_CONSORTIUM)
10457   {
10458     retp = ap->name->data;
10459   }
10460   return retp;
10461 }
10462 
GetAuthorListFieldSample(PubPtr pub,Int4 field_for_find)10463 static CharPtr GetAuthorListFieldSample (PubPtr pub, Int4 field_for_find)
10464 {
10465   CharPtr      retp = NULL;
10466   AuthListPtr  alp;
10467   ValNodePtr   names;
10468   AuthorPtr    ap;
10469 
10470   if (pub == NULL || field_for_find == PUB_FIELD_ANY)
10471   {
10472     return NULL;
10473   }
10474   alp = GetAuthorListForPub (pub);
10475   if (alp == NULL) return NULL;
10476 
10477   for (names = alp->names; names != NULL && retp == NULL; names = names->next)
10478   {
10479     ap = names->data.ptrvalue;
10480     retp = GetAuthorField (ap, field_for_find);
10481     if (StringHasNoText (retp))
10482     {
10483       retp = NULL;
10484     }
10485   }
10486   return retp;
10487 }
10488 
10489 
MakeNewInitials(NameStdPtr name_std)10490 static void MakeNewInitials (NameStdPtr name_std)
10491 {
10492   Char       frstinits [64];
10493   Int4       init_len;
10494   CharPtr    cp, middle_inits = NULL;
10495 
10496   if (name_std == NULL) return;
10497   FirstNameToInitials (name_std->names [1], frstinits, sizeof (frstinits) - 1);
10498   init_len = StringLen (name_std->names [1]) + StringLen (name_std->names [4]) + 1;
10499   if (name_std->names [4] != NULL)
10500   {
10501     cp = StringRChr (name_std->names [4], '.');
10502     if (cp != NULL)
10503     {
10504       cp ++;
10505       if (*cp != 0)
10506       {
10507         middle_inits = StringSave (cp);
10508       }
10509 
10510     }
10511   }
10512 
10513   name_std->names [4] = MemFree (name_std->names [4]);
10514   name_std->names [4] = (CharPtr) MemNew (sizeof (Char) * init_len);
10515   if (name_std->names [4] != NULL)
10516   {
10517     StringCpy (name_std->names [4], frstinits);
10518     if (middle_inits != NULL)
10519     {
10520       StringCat (name_std->names [4], middle_inits);
10521     }
10522   }
10523 }
10524 
SetMiddleInitial(NameStdPtr name_std,CharPtr init)10525 static void SetMiddleInitial (NameStdPtr name_std, CharPtr init)
10526 {
10527   CharPtr new_inits = NULL;
10528   Int4    first_init_len;
10529   Int4    len;
10530 
10531   if (name_std == NULL)
10532   {
10533     return;
10534   }
10535 
10536   first_init_len = StringLen (name_std->names[1]);
10537   len = first_init_len + StringLen (init) + 3;
10538   new_inits = (CharPtr) MemNew (len * sizeof (Char));
10539   if (new_inits != NULL)
10540   {
10541     FirstNameToInitials (name_std->names [1], new_inits,
10542                          first_init_len);
10543     StringCat (new_inits, ".");
10544     if (!StringHasNoText (init))
10545     {
10546       StringCat (new_inits, init);
10547       StringCat (new_inits, ".");
10548     }
10549 
10550     name_std->names[4] = MemFree (name_std->names[4]);
10551     name_std->names[4] = new_inits;
10552   }
10553 
10554 }
10555 
10556 
SetAuthorString(AuthorPtr ap,Int4 field_to_set,CharPtr str)10557 static void SetAuthorString (AuthorPtr ap, Int4 field_to_set, CharPtr str)
10558 {
10559   NameStdPtr name_std;
10560 
10561   if (field_to_set != PUB_FIELD_LAST_NAME &&
10562       (field_to_set == PUB_FIELD_LAST_NAME
10563       || field_to_set == PUB_FIELD_MIDDLE_INITIAL
10564       || field_to_set == PUB_FIELD_SUFFIX))
10565   {
10566     return;
10567   }
10568 
10569   if (field_to_set == PUB_FIELD_FIRST_NAME
10570       || field_to_set == PUB_FIELD_LAST_NAME
10571       || field_to_set == PUB_FIELD_MIDDLE_INITIAL
10572       || field_to_set == PUB_FIELD_SUFFIX)
10573   {
10574     if (ap->name->choice != 2)
10575     {
10576       name_std = NameStdNew ();
10577       if (name_std != NULL)
10578       {
10579         ap->name->data = MemFree (ap->name->data);
10580         ap->name->data = name_std;
10581         ap->name->choice = 2;
10582       }
10583     }
10584     if (ap->name->choice == 2)
10585     {
10586       name_std = (NameStdPtr) ap->name->data;
10587       if (field_to_set == PUB_FIELD_FIRST_NAME)
10588       {
10589         name_std->names[1] = MemFree (name_std->names[1]);
10590         name_std->names[1] = StringSave (str);
10591         MakeNewInitials (name_std);
10592       }
10593       else if (field_to_set == PUB_FIELD_LAST_NAME)
10594       {
10595         name_std->names[0] = MemFree (name_std->names[0]);
10596         name_std->names[0] = StringSave (str);
10597       }
10598       else if (field_to_set == PUB_FIELD_MIDDLE_INITIAL)
10599       {
10600         SetMiddleInitial (name_std, str);
10601       }
10602       else if (field_to_set == PUB_FIELD_SUFFIX)
10603       {
10604         name_std->names[5] = MemFree (name_std->names[5]);
10605         name_std->names[5] = StringSave (str);
10606       }
10607     }
10608   }
10609   else if (field_to_set == PUB_FIELD_CONSORTIUM)
10610   {
10611     if (ap->name->choice != 5)
10612     {
10613       if (ap->name->choice == 2)
10614       {
10615         ap->name->data = NameStdFree (ap->name->data);
10616       }
10617       else
10618       {
10619         ap->name->data = MemFree (ap->name->data);
10620       }
10621       ap->name->choice = 5;
10622     }
10623     if (ap->name->choice == 5)
10624     {
10625       ap->name->data = MemFree (ap->name->data);
10626       ap->name->data = StringSave (str);
10627     }
10628   }
10629 }
10630 
10631 
GetAffiliationFieldSample(PubPtr pub,Int4 field_for_find)10632 static CharPtr GetAffiliationFieldSample (PubPtr pub, Int4 field_for_find)
10633 {
10634   CharPtr      retp = NULL;
10635   AuthListPtr  alp;
10636   AffilPtr     affil;
10637 
10638   if (pub == NULL || field_for_find == PUB_FIELD_ANY)
10639   {
10640     return NULL;
10641   }
10642   alp = GetAuthorListForPub (pub);
10643   if (alp == NULL) return NULL;
10644 
10645   affil = alp->affil;
10646 
10647   if (affil == NULL) return NULL;
10648 
10649   switch (field_for_find)
10650   {
10651     case PUB_FIELD_INSTITUTION:
10652       retp = affil->affil;
10653       break;
10654     case PUB_FIELD_DEPARTMENT:
10655       retp = affil->div;
10656       break;
10657     case PUB_FIELD_ADDRESS:
10658       retp = affil->street;
10659       break;
10660     case PUB_FIELD_CITY:
10661       retp = affil->city;
10662       break;
10663     case PUB_FIELD_STATE:
10664       retp = affil->sub;
10665       break;
10666     case PUB_FIELD_COUNTRY:
10667       retp = affil->country;
10668       break;
10669     case PUB_FIELD_ZIP:
10670       retp = affil->postal_code;
10671       break;
10672     case PUB_FIELD_EMAIL:
10673       retp = affil->email;
10674       break;
10675     case PUB_FIELD_PHONE:
10676       retp = affil->phone;
10677       break;
10678     case PUB_FIELD_FAX:
10679       retp = affil->fax;
10680       break;
10681   }
10682   return retp;
10683 }
10684 
10685 
SetAffilString(AffilPtr affil,Int4 field_to_set,CharPtr str)10686 static AffilPtr SetAffilString (AffilPtr affil, Int4 field_to_set, CharPtr str)
10687 {
10688   if (affil == NULL)
10689   {
10690     affil = AffilNew ();
10691     if (affil == NULL) return NULL;
10692     affil->choice = 2;
10693   }
10694   else if (affil->choice != 2)
10695   {
10696     affil->choice = 2;
10697   }
10698   if (field_to_set == PUB_FIELD_INSTITUTION)
10699   {
10700     affil->affil = MemFree (affil->affil);
10701     affil->affil = StringSave (str);
10702   }
10703   else if (field_to_set == PUB_FIELD_DEPARTMENT)
10704   {
10705     affil->div = MemFree (affil->div);
10706     affil->div = StringSave (str);
10707   }
10708   else if (field_to_set == PUB_FIELD_ADDRESS)
10709   {
10710     affil->street = MemFree (affil->street);
10711     affil->street = StringSave (str);
10712   }
10713   else if (field_to_set == PUB_FIELD_CITY)
10714   {
10715     affil->city = MemFree (affil->city);
10716     affil->city = StringSave (str);
10717   }
10718   else if (field_to_set == PUB_FIELD_STATE)
10719   {
10720     affil->sub = MemFree (affil->sub);
10721     affil->sub = StringSave (str);
10722   }
10723   else if (field_to_set == PUB_FIELD_COUNTRY)
10724   {
10725     affil->country = MemFree (affil->country);
10726     affil->country = StringSave (str);
10727   }
10728   else if (field_to_set == PUB_FIELD_ZIP)
10729   {
10730     affil->postal_code = MemFree (affil->postal_code);
10731     affil->postal_code = StringSave (str);
10732   }
10733   else if (field_to_set == PUB_FIELD_EMAIL)
10734   {
10735     affil->email = MemFree (affil->email);
10736     affil->email = StringSave (str);
10737   }
10738   else if (field_to_set == PUB_FIELD_PHONE)
10739   {
10740     affil->phone = MemFree (affil->phone);
10741     affil->phone = StringSave (str);
10742   }
10743   else if (field_to_set == PUB_FIELD_FAX)
10744   {
10745     affil->fax = MemFree (affil->fax);
10746     affil->fax = StringSave (str);
10747   }
10748   return affil;
10749 }
10750 
10751 
GetSampleStringFromPub(PubdescPtr pdp,Int4 field_num)10752 static CharPtr GetSampleStringFromPub (PubdescPtr pdp, Int4 field_num)
10753 {
10754   PubPtr       pub;
10755   CharPtr      retp = NULL;
10756 
10757   if (pdp == NULL || pdp->pub == NULL || field_num == PUB_FIELD_ANY)
10758   {
10759     return NULL;
10760   }
10761 
10762   for (pub = pdp->pub; pub != NULL && retp == NULL; pub = pub->next)
10763   {
10764     switch (field_num)
10765     {
10766       case PUB_FIELD_TITLE:
10767         retp = GetPubTitleSample (pub);
10768         break;
10769       case PUB_FIELD_FIRST_NAME:
10770       case PUB_FIELD_MIDDLE_INITIAL:
10771       case PUB_FIELD_LAST_NAME:
10772       case PUB_FIELD_SUFFIX:
10773       case PUB_FIELD_CONSORTIUM:
10774         retp = GetAuthorListFieldSample (pub, field_num);
10775         break;
10776       case PUB_FIELD_INSTITUTION:
10777       case PUB_FIELD_DEPARTMENT:
10778       case PUB_FIELD_ADDRESS:
10779       case PUB_FIELD_CITY:
10780       case PUB_FIELD_STATE:
10781       case PUB_FIELD_COUNTRY:
10782       case PUB_FIELD_ZIP:
10783       case PUB_FIELD_EMAIL:
10784       case PUB_FIELD_PHONE:
10785       case PUB_FIELD_FAX:
10786         retp = GetAffiliationFieldSample (pub, field_num);
10787         break;
10788     }
10789     if (StringHasNoText (retp))
10790     {
10791       retp = NULL;
10792     }
10793   }
10794   return retp;
10795 }
10796 
10797 
GetPubStatus(PubPtr the_pub)10798 static Int4 GetPubStatus (PubPtr the_pub)
10799 {
10800   CitGenPtr  cgp;
10801   CitSubPtr  csp;
10802   CitArtPtr  cap;
10803   CitBookPtr cbp;
10804   CitJourPtr cjp;
10805   ImprintPtr imp = NULL;
10806   Int4       status = PUB_STAT_ANY;
10807 
10808   while (the_pub != NULL && status == PUB_STAT_ANY)
10809   {
10810     if (the_pub->data.ptrvalue != NULL)
10811     {
10812       switch (the_pub->choice)
10813       {
10814         case PUB_Gen :
10815           cgp = (CitGenPtr) the_pub->data.ptrvalue;
10816           if (cgp->cit != NULL && StringICmp (cgp->cit, "unpublished") == 0)
10817           {
10818             status = PUB_STAT_UNPUBLISHED;
10819           }
10820           else
10821           {
10822             status = PUB_STAT_PUBLISHED;
10823           }
10824           break;
10825         case PUB_Sub :
10826           csp = (CitSubPtr) the_pub->data.ptrvalue;
10827           status = PUB_STAT_PUBLISHED_SUBMISSION;
10828           break;
10829         case PUB_Article :
10830           cap = (CitArtPtr) the_pub->data.ptrvalue;
10831           if (cap->from == 1)
10832           {
10833             cjp = (CitJourPtr) cap->fromptr;
10834             if (cjp != NULL)
10835             {
10836               imp = cjp->imp;
10837             }
10838           }
10839 	      else if (cap->from == 2 || cap->from == 3)
10840 	      {
10841             cbp = (CitBookPtr) cap->fromptr;
10842 		    if (cbp != NULL) {
10843               imp = cbp->imp;
10844 		    }
10845 	      }
10846           break;
10847         case PUB_Journal :
10848           cjp = (CitJourPtr) the_pub->data.ptrvalue;
10849           imp = cjp->imp;
10850         case PUB_Book :
10851         case PUB_Man :
10852           cbp = (CitBookPtr) the_pub->data.ptrvalue;
10853           imp = cbp->imp;
10854           break;
10855         case PUB_Patent :
10856           status = PUB_STAT_PUBLISHED;
10857           break;
10858         default :
10859           break;
10860 
10861       }
10862       if (imp != NULL)
10863       {
10864         if (imp->prepub == 0)
10865         {
10866           status = PUB_STAT_PUBLISHED;
10867         }
10868         else if (imp->prepub == 2)
10869         {
10870           status = PUB_STAT_INPRESS;
10871         }
10872         else if (imp->prepub == 1 && the_pub->choice == PUB_Sub)
10873         {
10874           status = PUB_STAT_PUBLISHED_SUBMISSION;
10875         }
10876         else
10877         {
10878           status = PUB_STAT_UNPUBLISHED;
10879         }
10880       }
10881     }
10882     the_pub = the_pub->next;
10883   }
10884   return status;
10885 }
10886 
10887 /* The following functions are used to determine whether a particular section of a
10888  * publication matches the value specified in the PubConstraint.
10889  */
DoesPubTitleMatchConstraint(PubPtr the_pub,PubConstraintPtr p)10890 static Boolean DoesPubTitleMatchConstraint (PubPtr the_pub, PubConstraintPtr p)
10891 {
10892   CitGenPtr  cgp;
10893   CitArtPtr  cap;
10894   CitBookPtr cbp;
10895   CitPatPtr  cpp;
10896   Boolean    rval = FALSE;
10897   CharPtr    title;
10898 
10899   if (the_pub == NULL || p == NULL || the_pub->data.ptrvalue == NULL)
10900   {
10901     return FALSE;
10902   }
10903   if (p->find_str == NULL) return TRUE;
10904 
10905   switch (the_pub->choice) {
10906     case PUB_Gen :
10907       cgp = (CitGenPtr) the_pub->data.ptrvalue;
10908       if ((p->insensitive_to_case
10909            && StringISearch (cgp->title, p->find_str) != NULL)
10910           || StringSearch (cgp->title, p->find_str) != NULL)
10911       {
10912         rval = TRUE;
10913       }
10914       break;
10915     case PUB_Sub :
10916       break;
10917     case PUB_Article :
10918       cap = (CitArtPtr) the_pub->data.ptrvalue;
10919       if(cap->title != NULL)
10920       {
10921         title = (CharPtr) (cap->title->data.ptrvalue);
10922         if ((p->insensitive_to_case
10923              && StringISearch (title, p->find_str) != NULL)
10924             || StringSearch (title, p->find_str) != NULL)
10925         {
10926           rval = TRUE;
10927         }
10928       }
10929       break;
10930     case PUB_Book :
10931     case PUB_Man :
10932       cbp = (CitBookPtr) the_pub->data.ptrvalue;
10933       if(cbp->title != NULL) {
10934         title = (CharPtr) (cbp->title->data.ptrvalue);
10935         if ((p->insensitive_to_case
10936              && StringISearch (title, p->find_str) != NULL)
10937             || StringSearch (title, p->find_str) != NULL)
10938         {
10939           rval = TRUE;
10940         }
10941       }
10942       break;
10943     case PUB_Patent :
10944       cpp = (CitPatPtr) the_pub->data.ptrvalue;
10945       if ((p->insensitive_to_case
10946            && StringISearch (cpp->title, p->find_str) != NULL)
10947           || StringSearch (cpp->title, p->find_str) != NULL)
10948       {
10949         rval = TRUE;
10950       }
10951       break;
10952     default :
10953       break;
10954   }
10955 
10956   return rval;
10957 }
10958 
DoesAffiliationMatchString(AffilPtr ap,PubConstraintPtr p)10959 static Boolean DoesAffiliationMatchString (AffilPtr ap, PubConstraintPtr p)
10960 {
10961   Boolean rval = FALSE;
10962 
10963   if (ap == NULL || p == NULL) return FALSE;
10964 
10965   if (p->find_str == NULL) return TRUE;
10966 
10967   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_INSTITUTION)
10968       && ((p->insensitive_to_case && StringISearch (ap->affil, p->find_str) != NULL)
10969         || StringSearch (ap->affil, p->find_str) != NULL))
10970   {
10971     rval = TRUE;
10972   }
10973   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_DEPARTMENT)
10974       && ((p->insensitive_to_case && StringISearch (ap->div, p->find_str) != NULL)
10975         || StringSearch (ap->div, p->find_str) != NULL))
10976   {
10977     rval = TRUE;
10978   }
10979   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_ADDRESS)
10980       && ((p->insensitive_to_case && StringISearch (ap->street, p->find_str) != NULL)
10981         || StringSearch (ap->street, p->find_str) != NULL))
10982   {
10983     rval = TRUE;
10984   }
10985   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_CITY)
10986       && ((p->insensitive_to_case && StringISearch (ap->city, p->find_str) != NULL)
10987         || StringSearch (ap->city, p->find_str) != NULL))
10988   {
10989     rval = TRUE;
10990   }
10991   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_STATE)
10992       && ((p->insensitive_to_case && StringISearch (ap->sub, p->find_str) != NULL)
10993         || StringSearch (ap->sub, p->find_str) != NULL))
10994   {
10995     rval = TRUE;
10996   }
10997   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_COUNTRY)
10998       && ((p->insensitive_to_case && StringISearch (ap->country, p->find_str) != NULL)
10999         || StringSearch (ap->country, p->find_str) != NULL))
11000   {
11001     rval = TRUE;
11002   }
11003   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_EMAIL)
11004       && ((p->insensitive_to_case && StringISearch (ap->email, p->find_str) != NULL)
11005         || StringSearch (ap->email, p->find_str) != NULL))
11006   {
11007     rval = TRUE;
11008   }
11009   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_ZIP)
11010       && ((p->insensitive_to_case && StringISearch (ap->postal_code, p->find_str) != NULL)
11011         || StringSearch (ap->postal_code, p->find_str) != NULL))
11012   {
11013     rval = TRUE;
11014   }
11015   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_PHONE)
11016       && ((p->insensitive_to_case && StringISearch (ap->phone, p->find_str) != NULL)
11017         || StringSearch (ap->phone, p->find_str) != NULL))
11018   {
11019     rval = TRUE;
11020   }
11021   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_FAX)
11022       && ((p->insensitive_to_case && StringISearch (ap->fax, p->find_str) != NULL)
11023         || StringSearch (ap->fax, p->find_str) != NULL))
11024   {
11025     rval = TRUE;
11026   }
11027   return rval;
11028 }
11029 
11030 
DoesOneAuthorMatchString(AuthorPtr ap,PubConstraintPtr p)11031 static Boolean DoesOneAuthorMatchString (AuthorPtr ap, PubConstraintPtr p)
11032 {
11033   Boolean rval = FALSE;
11034   NameStdPtr pNameStandard = NULL;
11035 
11036   if (ap == NULL || p == NULL) return FALSE;
11037   if (p->find_str == NULL) return TRUE;
11038 
11039   if (ap->name->choice == 2)
11040   {
11041     pNameStandard = (NameStdPtr) ap->name->data;
11042     if (((p->field_for_find == PUB_FIELD_ANY
11043          || p->field_for_find == PUB_FIELD_FIRST_NAME))
11044         && ((p->insensitive_to_case && StringISearch (pNameStandard->names[1], p->find_str) != NULL)
11045           || StringSearch (pNameStandard->names[1], p->find_str) != NULL))
11046     {
11047       rval = TRUE;
11048     }
11049     if (((p->field_for_find == PUB_FIELD_ANY
11050        || p->field_for_find == PUB_FIELD_LAST_NAME))
11051         && ((p->insensitive_to_case && StringISearch (pNameStandard->names[0], p->find_str) != NULL)
11052           || StringSearch (pNameStandard->names[0], p->find_str) != NULL))
11053     {
11054       rval = TRUE;
11055     }
11056     if (((p->field_for_find == PUB_FIELD_ANY
11057         || p->field_for_find == PUB_FIELD_MIDDLE_INITIAL))
11058          && ((p->insensitive_to_case && StringISearch (pNameStandard->names[2], p->find_str) != NULL)
11059           || StringSearch (pNameStandard->names[2], p->find_str) != NULL))
11060     {
11061       rval = TRUE;
11062     }
11063     if (((p->field_for_find == PUB_FIELD_ANY
11064         || p->field_for_find == PUB_FIELD_SUFFIX))
11065          && ((p->insensitive_to_case && StringICmp (pNameStandard->names[5], p->find_str) == 0)
11066           || StringCmp (pNameStandard->names[5], p->find_str) == 0))
11067     {
11068       rval = TRUE;
11069     }
11070   }
11071   if (ap->name->choice == 5
11072       && (p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_CONSORTIUM)
11073       && ((p->insensitive_to_case && StringISearch (ap->name->data, p->find_str) != NULL)
11074         || StringSearch (ap->name->data, p->find_str) != NULL))
11075   {
11076     rval = TRUE;
11077   }
11078 
11079   return rval;
11080 }
11081 
11082 
DoesAuthorListMatchConstraint(AuthListPtr alp,PubConstraintPtr p)11083 static Boolean DoesAuthorListMatchConstraint (AuthListPtr alp, PubConstraintPtr p)
11084 {
11085   Boolean    rval = FALSE;
11086   ValNodePtr	names;
11087   AuthorPtr   ap;
11088 
11089   if (alp == NULL || p == NULL)
11090   {
11091     return FALSE;
11092   }
11093   if (p->find_str == NULL) return TRUE;
11094 
11095   for (names = alp->names; names != NULL && !rval; names = names->next)
11096   {
11097     ap = names->data.ptrvalue;
11098     rval = DoesOneAuthorMatchString (ap, p);
11099   }
11100 
11101   return rval;
11102 }
11103 
11104 
DoesPubMatchConstraint(PubPtr the_pub,PubConstraintPtr p)11105 static Boolean DoesPubMatchConstraint (PubPtr the_pub, PubConstraintPtr p)
11106 {
11107   Boolean     rval = FALSE;
11108   AuthListPtr alp;
11109 
11110   if (the_pub == NULL || p == NULL) return FALSE;
11111 
11112   if (p->pub_status != PUB_STAT_ANY && p->pub_status != GetPubStatus (the_pub))
11113   {
11114     return FALSE;
11115   }
11116   if ((p->field_for_find == PUB_FIELD_ANY || p->field_for_find == PUB_FIELD_TITLE)
11117       && DoesPubTitleMatchConstraint (the_pub, p))
11118   {
11119     rval = TRUE;
11120   }
11121   if (!rval)
11122   {
11123     alp = GetAuthorListForPub (the_pub);
11124     if (alp != NULL)
11125     {
11126       rval = DoesAuthorListMatchConstraint (alp, p);
11127       if (!rval && DoesAffiliationMatchString (alp->affil, p))
11128       {
11129         rval = TRUE;
11130       }
11131     }
11132   }
11133   return rval;
11134 }
11135 
11136 
11137 /* This structure is used for the Edit Publications dialog.
11138  * It contains a PubConstraint plus the necessary controls
11139  * to collect user input for editing a single field,
11140  * replacing a publication section, or merging author lists.
11141  */
11142 typedef struct EditPubform
11143 {
11144   FORM_MESSAGE_BLOCK
11145 
11146   DialoG            pub_constraint_dlg;
11147   ButtoN            leaveDlgUp;
11148 
11149   PubConstraintPtr  pcp;
11150 
11151   /* used for single field replace */
11152   TexT              repl_string_txt;
11153   DialoG            field_to_set_dlg;
11154   CharPtr           repl_string;
11155   Int4              field_to_set;
11156 
11157   /* used for replacing publication section */
11158   ButtoN            replace_author_list;
11159   ButtoN            replace_title;
11160   ButtoN            replace_affiliation;
11161   PubdescPtr        pdp;
11162   AuthListPtr       alp;
11163   CharPtr           title_str;
11164   AffilPtr          affil;
11165 
11166   /* used for author list merge */
11167   ValNodePtr        names_list;
11168 
11169   GrouP             edit_type_group;
11170   Int4              edit_type;
11171   GrouP             single_field_group;
11172   GrouP             replace_sect_group;
11173   GrouP             merge_auth_list_group;
11174   GrouP             specify_author_order;
11175   GrouP             replace_pub_group;
11176 
11177   /* used for publication replace */
11178   Boolean           found_conflict;
11179   Boolean           found_one_pub;
11180   Boolean           found_any_pubs;
11181   PubdescPtr        replacement_pdp;
11182 
11183   /* used for updating feature citations */
11184   ValNodePtr        affected_pubs;
11185 } EditPubFormData, PNTR EditPubFormPtr;
11186 
11187 typedef struct affectedpubpair
11188 {
11189   PubdescPtr orig; /* this is a copy and should be freed */
11190   PubdescPtr curr; /* this is not a copy and should not be freed */
11191 } AffectedPubPairData, PNTR AffectedPubPairPtr;
11192 
AffectedPubPairListFree(ValNodePtr pair_list)11193 static ValNodePtr AffectedPubPairListFree (ValNodePtr pair_list)
11194 {
11195   AffectedPubPairPtr appp;
11196 
11197   if (pair_list == NULL)
11198   {
11199     return NULL;
11200   }
11201   pair_list->next = AffectedPubPairListFree (pair_list->next);
11202   appp = (AffectedPubPairPtr) pair_list->data.ptrvalue;
11203   if (appp != NULL)
11204   {
11205     appp->orig = PubdescFree (appp->orig);
11206   }
11207   pair_list = ValNodeFreeData (pair_list);
11208   return pair_list;
11209 }
11210 
11211 typedef Boolean (LIBCALLBACK *operateOnPubFunction) (
11212   PubPtr pub,
11213   EditPubFormPtr epfp
11214 );
11215 
11216 typedef struct operatepub
11217 {
11218   operateOnPubFunction op_pub;
11219   EditPubFormPtr       epfp;
11220 } OperatePubData, PNTR OperatePubPtr;
11221 
OperateOnPubFeatureCallback(SeqFeatPtr sfp,Pointer userdata)11222 static void OperateOnPubFeatureCallback (SeqFeatPtr sfp, Pointer userdata)
11223 {
11224   OperatePubPtr       opp;
11225   PubPtr              pub;
11226   PubdescPtr          pdp, pdp_copy;
11227   Boolean             changed = FALSE;
11228   AffectedPubPairPtr  appp;
11229 
11230   if (sfp == NULL || sfp->data.choice != SEQFEAT_PUB || userdata == NULL)
11231   {
11232     return;
11233   }
11234   opp = (OperatePubPtr) userdata;
11235   if (opp->op_pub == NULL || opp->epfp == NULL) return;
11236   pdp = (PubdescPtr) sfp->data.value.ptrvalue;
11237   if (pdp == NULL) return;
11238   pdp_copy = (PubdescPtr) AsnIoMemCopy (pdp, (AsnReadFunc) PubdescAsnRead,
11239                                              (AsnWriteFunc) PubdescAsnWrite);
11240   for (pub = pdp->pub; pub != NULL; pub = pub->next)
11241   {
11242     changed |= opp->op_pub (pub, opp->epfp);
11243   }
11244 
11245   if (changed)
11246   {
11247     appp = (AffectedPubPairPtr) MemNew (sizeof (AffectedPubPairData));
11248     if (appp != NULL)
11249     {
11250       appp->orig = pdp_copy;
11251       appp->curr = pdp;
11252       ValNodeAddPointer (&(opp->epfp->affected_pubs), 0, appp);
11253       pdp_copy = NULL;
11254     }
11255   }
11256   pdp_copy = PubdescFree (pdp_copy);
11257 }
11258 
OperateOnPubDescriptorCallback(SeqDescPtr sdp,Pointer userdata)11259 static void OperateOnPubDescriptorCallback (SeqDescPtr sdp, Pointer userdata)
11260 {
11261   OperatePubPtr       opp;
11262   PubPtr              pub;
11263   PubdescPtr          pdp, pdp_copy;
11264   Boolean             changed = FALSE;
11265   AffectedPubPairPtr  appp;
11266 
11267   if (sdp == NULL || sdp->choice != Seq_descr_pub || userdata == NULL)
11268   {
11269     return;
11270   }
11271   opp = (OperatePubPtr) userdata;
11272   if (opp->op_pub == NULL || opp->epfp == NULL) return;
11273   pdp = (PubdescPtr) sdp->data.ptrvalue;
11274   if (pdp == NULL) return;
11275   pdp_copy = (PubdescPtr) AsnIoMemCopy (pdp, (AsnReadFunc) PubdescAsnRead,
11276                                              (AsnWriteFunc) PubdescAsnWrite);
11277   for (pub = pdp->pub; pub != NULL; pub = pub->next)
11278   {
11279     changed |= opp->op_pub (pub, opp->epfp);
11280   }
11281   if (changed)
11282   {
11283     appp = (AffectedPubPairPtr) MemNew (sizeof (AffectedPubPairData));
11284     if (appp != NULL)
11285     {
11286       appp->orig = pdp_copy;
11287       appp->curr = pdp;
11288       ValNodeAddPointer (&(opp->epfp->affected_pubs), 0, appp);
11289       pdp_copy = NULL;
11290     }
11291   }
11292   pdp_copy = PubdescFree (pdp_copy);
11293 }
11294 
11295 
OperateOnPubByConstraint(SeqEntryPtr sep,EditPubFormPtr epfp,operateOnPubFunction op_pub)11296 static void OperateOnPubByConstraint (SeqEntryPtr sep, EditPubFormPtr epfp, operateOnPubFunction op_pub)
11297 {
11298   OperatePubData opd;
11299 
11300   if (sep == NULL || epfp == NULL || op_pub == NULL) return;
11301   opd.epfp = epfp;
11302   opd.op_pub = op_pub;
11303 
11304   VisitFeaturesInSep (sep, &opd, OperateOnPubFeatureCallback);
11305   VisitDescriptorsInSep (sep, &opd, OperateOnPubDescriptorCallback);
11306 
11307 }
11308 
11309 /* The following code is used for setting the value of a single field
11310  * in a publication.
11311  */
SetFieldByConstraint(PubPtr pdp,PubConstraintPtr p,Int4 field_to_set,CharPtr str,ValNodePtr PNTR affected_pubs)11312 static Boolean SetFieldByConstraint
11313 (PubPtr           pdp,
11314  PubConstraintPtr p,
11315  Int4             field_to_set,
11316  CharPtr          str,
11317  ValNodePtr PNTR  affected_pubs)
11318 {
11319   ValNodePtr  names;
11320   AuthListPtr alp;
11321   AuthorPtr   ap;
11322   Boolean     changed = FALSE;
11323 
11324   if (pdp == NULL || p == NULL ||
11325       (p->pub_status != PUB_STAT_ANY && p->pub_status != GetPubStatus (pdp)))
11326   {
11327     return FALSE;
11328   }
11329 
11330   if (field_to_set == PUB_FIELD_TITLE)
11331   {
11332     if (DoesPubMatchConstraint (pdp, p))
11333     {
11334       SetPubTitle (pdp, str);
11335       changed = TRUE;
11336     }
11337   }
11338   else if (field_to_set >= PUB_FIELD_FIRST_NAME
11339            && field_to_set <= PUB_FIELD_CONSORTIUM)
11340   {
11341     alp = GetAuthorListForPub (pdp);
11342     if (alp == NULL)
11343     {
11344       alp = AuthListNew ();
11345       if (! SetPubAuthorList (pdp, alp))
11346       {
11347         MemFree (alp);
11348         return FALSE;
11349       }
11350     }
11351     if ((p->field_for_find == PUB_FIELD_TITLE && DoesPubTitleMatchConstraint (pdp, p))
11352       || (p->field_for_find >= PUB_FIELD_INSTITUTION && p->field_for_find <= PUB_FIELD_FAX
11353           && DoesAffiliationMatchString (alp->affil, p)))
11354     {
11355       for (names = alp->names; names != NULL; names = names->next)
11356       {
11357         SetAuthorString (names->data.ptrvalue, field_to_set, str);
11358       }
11359       changed = TRUE;
11360     }
11361     else if (p->field_for_find >= PUB_FIELD_FIRST_NAME
11362              && p->field_for_find <= PUB_FIELD_CONSORTIUM)
11363     {
11364       if (field_to_set == PUB_FIELD_CONSORTIUM)
11365       {
11366         for (names = alp->names; names != NULL; names = names->next)
11367         {
11368           ap = (AuthorPtr) names->data.ptrvalue;
11369           if (ap != NULL && ap->name->choice == 5 && DoesOneAuthorMatchString (ap, p))
11370           {
11371             SetAuthorString (ap, field_to_set, str);
11372             changed = TRUE;
11373           }
11374         }
11375       }
11376       else
11377       {
11378         for (names = alp->names; names != NULL; names = names->next)
11379         {
11380           if (DoesOneAuthorMatchString (names->data.ptrvalue, p))
11381           {
11382             SetAuthorString (names->data.ptrvalue, field_to_set, str);
11383             changed = TRUE;
11384           }
11385         }
11386       }
11387     }
11388     else if (p->field_for_find == PUB_FIELD_ANY)
11389     {
11390       if (field_to_set == PUB_FIELD_CONSORTIUM)
11391       {
11392         for (names = alp->names; names != NULL; names = names->next)
11393         {
11394           ap = (AuthorPtr) names->data.ptrvalue;
11395           if (ap != NULL && ap->name->choice == 5)
11396           {
11397             SetAuthorString (ap, field_to_set, str);
11398             changed = TRUE;
11399           }
11400         }
11401       }
11402       else
11403       {
11404         for (names = alp->names; names != NULL; names = names->next)
11405         {
11406           SetAuthorString (names->data.ptrvalue, field_to_set, str);
11407           changed = TRUE;
11408         }
11409       }
11410     }
11411   }
11412   else if (field_to_set >= PUB_FIELD_INSTITUTION
11413            && field_to_set <= PUB_FIELD_FAX
11414            )
11415   {
11416     alp = GetAuthorListForPub (pdp);
11417     if (alp == NULL)
11418     {
11419       alp = AuthListNew ();
11420       if (! SetPubAuthorList (pdp, alp))
11421       {
11422         MemFree (alp);
11423         return FALSE;
11424       }
11425     }
11426     if (DoesPubMatchConstraint (pdp, p))
11427     {
11428       alp->affil = SetAffilString (alp->affil, field_to_set, str);
11429       changed = TRUE;
11430     }
11431   }
11432   return changed;
11433 }
11434 
EditPubSingleField(PubPtr pub,EditPubFormPtr epfp)11435 static Boolean LIBCALLBACK EditPubSingleField (PubPtr pub, EditPubFormPtr epfp)
11436 {
11437   if (pub == NULL || epfp == NULL) return FALSE;
11438 
11439   return SetFieldByConstraint (pub, epfp->pcp, epfp->field_to_set, epfp->repl_string,
11440                         &(epfp->affected_pubs));
11441 }
11442 
11443 
11444 /* this code is used for replacing pub sections */
ReplacePubSectByConstraint(PubPtr pub,EditPubFormPtr epfp)11445 static Boolean LIBCALLBACK ReplacePubSectByConstraint (PubPtr pub, EditPubFormPtr epfp)
11446 {
11447   AuthListPtr alp;
11448   Boolean     changed = FALSE;
11449 
11450   if (pub == NULL || epfp == NULL)
11451   {
11452     return FALSE;
11453   }
11454   if (DoesPubMatchConstraint (pub, epfp->pcp))
11455   {
11456     if (epfp->alp != NULL)
11457     {
11458       alp = AsnIoMemCopy ((Pointer) epfp->alp,
11459                     (AsnReadFunc) AuthListAsnRead,
11460                     (AsnWriteFunc) AuthListAsnWrite);
11461       if (alp != NULL)
11462       {
11463         SetPubAuthorList (pub, alp);
11464       }
11465     }
11466     if (epfp->title_str != NULL)
11467     {
11468       SetPubTitle (pub, epfp->title_str);
11469     }
11470     if (epfp->affil != NULL)
11471     {
11472       alp = GetAuthorListForPub (pub);
11473       if (alp != NULL)
11474       {
11475         alp->affil = AffilFree (alp->affil);
11476         alp->affil = AsnIoMemCopy ((Pointer) epfp->affil,
11477                          (AsnReadFunc) AffilAsnRead,
11478                          (AsnWriteFunc) AffilAsnWrite);
11479       }
11480     }
11481     changed = TRUE;
11482   }
11483   return changed;
11484 }
11485 
11486 
11487 /* this code is used for merging author lists */
AreAuthorNamesIdentical(AuthorPtr ap1,AuthorPtr ap2)11488 static Boolean AreAuthorNamesIdentical (AuthorPtr ap1, AuthorPtr ap2)
11489 {
11490   NameStdPtr   pNameStandard1, pNameStandard2;
11491   CharPtr      n1, n2;
11492   Boolean      rval = FALSE;
11493   Int4         idx;
11494 
11495   if (ap1 == NULL || ap2 == NULL) return FALSE;
11496 
11497   if (ap1->name->choice != ap2->name->choice)
11498   {
11499     rval = FALSE;
11500   }
11501   else
11502   {
11503     switch (ap1->name->choice)
11504     {
11505       case 2:
11506         pNameStandard1 = (NameStdPtr) ap1->name->data;
11507         pNameStandard2 = (NameStdPtr) ap2->name->data;
11508         rval = TRUE;
11509         for (idx = 0; idx < 7 && rval; idx++)
11510         {
11511           if (StringHasNoText (pNameStandard1->names[idx]))
11512           {
11513             if (!StringHasNoText (pNameStandard2->names[idx]))
11514             {
11515               rval = FALSE;
11516             }
11517           }
11518           else if (StringHasNoText (pNameStandard2->names[idx]))
11519           {
11520             rval = FALSE;
11521           }
11522           else if (StringCmp (pNameStandard1->names[idx], pNameStandard2->names[idx]) != 0)
11523           {
11524             rval = FALSE;
11525           }
11526         }
11527         break;
11528       case 4:
11529       case 5:
11530         n1 = (CharPtr) ap1->name->data;
11531         n2 = (CharPtr) ap2->name->data;
11532         if (StringCmp (n1, n2) == 0)
11533         {
11534           rval = TRUE;
11535         }
11536         break;
11537     }
11538   }
11539 
11540   return rval;
11541 }
11542 
GetMergedAuthorListByConstraint(PubPtr pub,EditPubFormPtr epfp)11543 static Boolean LIBCALLBACK GetMergedAuthorListByConstraint (PubPtr pub, EditPubFormPtr epfp)
11544 {
11545   AuthListPtr alp;
11546   ValNodePtr  name_in_this, name_in_list;
11547   AuthorPtr   ap1, ap2;
11548   Boolean     found_match;
11549   Boolean     changed = FALSE;
11550 
11551   if (pub == NULL || epfp == NULL)
11552   {
11553     return FALSE;
11554   }
11555   if (DoesPubMatchConstraint (pub, epfp->pcp))
11556   {
11557     alp = GetAuthorListForPub (pub);
11558     if (alp != NULL)
11559     {
11560       for (name_in_this = alp->names; name_in_this != NULL; name_in_this = name_in_this->next)
11561       {
11562         ap1 = name_in_this->data.ptrvalue;
11563         found_match = FALSE;
11564         for (name_in_list = epfp->names_list;
11565              name_in_list != NULL && !found_match;
11566              name_in_list = name_in_list->next)
11567         {
11568           ap2 = name_in_list->data.ptrvalue;
11569           if (AreAuthorNamesIdentical (ap1, ap2))
11570           {
11571             found_match = TRUE;
11572           }
11573         }
11574         if (!found_match)
11575         {
11576           ap2 = AsnIoMemCopy ((Pointer) ap1,
11577                     (AsnReadFunc) AuthorAsnRead,
11578                     (AsnWriteFunc) AuthorAsnWrite);
11579           if (ap2 != NULL)
11580           {
11581             ValNodeAddPointer (&(epfp->names_list), name_in_this->choice, ap2);
11582           }
11583         }
11584       }
11585     }
11586     changed = TRUE;
11587   }
11588   return changed;
11589 }
11590 
FreeAuthorNameList(ValNodePtr names_list)11591 static ValNodePtr FreeAuthorNameList (ValNodePtr names_list)
11592 {
11593   ValNodePtr vnp;
11594 
11595   for (vnp = names_list; vnp != NULL; vnp = vnp->next)
11596   {
11597     vnp->data.ptrvalue = AuthorFree (vnp->data.ptrvalue);
11598   }
11599   names_list = ValNodeFree (names_list);
11600   return names_list;
11601 }
11602 
ReplaceNameList(AuthListPtr alp,ValNodePtr new_name_list)11603 static void ReplaceNameList (AuthListPtr alp, ValNodePtr new_name_list)
11604 {
11605   ValNodePtr  new_name;
11606   AuthorPtr   new_ap;
11607 
11608   if (alp == NULL) return;
11609 
11610   alp->names = FreeAuthorNameList (alp->names);
11611 
11612   for (new_name = new_name_list; new_name != NULL; new_name = new_name->next)
11613   {
11614     new_ap = AsnIoMemCopy (new_name->data.ptrvalue,
11615                     (AsnReadFunc) AuthorAsnRead,
11616                     (AsnWriteFunc) AuthorAsnWrite);
11617     if (new_ap != NULL)
11618     {
11619       ValNodeAddPointer (&(alp->names), new_name->choice, new_ap);
11620     }
11621   }
11622 }
11623 
SetMergedAuthorListByConstraint(PubPtr pub,EditPubFormPtr epfp)11624 static Boolean LIBCALLBACK SetMergedAuthorListByConstraint (PubPtr pub, EditPubFormPtr epfp)
11625 {
11626   AuthListPtr alp;
11627   Boolean     changed = FALSE;
11628 
11629   if (pub == NULL || epfp == NULL)
11630   {
11631     return FALSE;
11632   }
11633   if (DoesPubMatchConstraint (pub, epfp->pcp))
11634   {
11635     alp = GetAuthorListForPub (pub);
11636     ReplaceNameList (alp, epfp->names_list);
11637     changed = TRUE;
11638   }
11639   return changed;
11640 }
11641 
11642 
FindFirstSelectedPub(void)11643 static PubdescPtr FindFirstSelectedPub (void)
11644 {
11645   SelStructPtr          ssp;
11646   SeqFeatPtr            sfp;
11647   SeqDescrPtr           sdp;
11648   PubdescPtr            pdp = NULL;
11649   SeqMgrFeatContext     fcontext;
11650   SeqMgrDescContext     dcontext;
11651 
11652 
11653   /* find the selected pub */
11654   ssp  = ObjMgrGetSelected();
11655 
11656   while (NULL != ssp && pdp == NULL)
11657   {
11658     if (ssp->itemtype == OBJ_SEQFEAT)
11659     {
11660       sfp = SeqMgrGetDesiredFeature (ssp->entityID, NULL, ssp->itemID, 0, NULL, &fcontext);
11661       if (sfp != NULL && sfp->data.choice == SEQFEAT_PUB)
11662       {
11663         pdp = sfp->data.value.ptrvalue;
11664       }
11665     }
11666     else if (ssp->itemtype == OBJ_SEQDESC)
11667     {
11668       sdp = SeqMgrGetDesiredDescriptor (ssp->entityID, NULL, ssp->itemID, 0, NULL, &dcontext);
11669       if (sdp != NULL && sdp->choice == Seq_descr_pub)
11670       {
11671         pdp = sdp->data.ptrvalue;
11672       }
11673     }
11674     ssp = ssp->next;
11675   }
11676   return pdp;
11677 }
11678 
PubdescIsSubmitterBlock(PubdescPtr pdp)11679 static Boolean PubdescIsSubmitterBlock (PubdescPtr pdp)
11680 {
11681   Boolean is_submitter_block = FALSE;
11682   PubPtr  pub;
11683 
11684   if (pdp == NULL) return FALSE;
11685   for (pub = pdp->pub; pub != NULL && ! is_submitter_block; pub = pub->next)
11686   {
11687     if (pub->choice == PUB_Sub)
11688     {
11689       is_submitter_block = TRUE;
11690     }
11691   }
11692   return is_submitter_block;
11693 }
11694 
FindPubReplaceConflictsInDescr(SeqDescrPtr sdp,EditPubFormPtr epfp)11695 static void FindPubReplaceConflictsInDescr (SeqDescrPtr sdp, EditPubFormPtr epfp)
11696 {
11697   Boolean    this_pub_matches;
11698   PubPtr     pub;
11699   PubdescPtr pdp;
11700   Boolean    repl_is_submitter_block;
11701   Boolean    this_is_submitter_block;
11702 
11703   if (sdp == NULL || epfp == NULL) return;
11704 
11705   repl_is_submitter_block = PubdescIsSubmitterBlock (epfp->replacement_pdp);
11706 
11707   while (sdp != NULL && ! epfp->found_conflict)
11708   {
11709     this_pub_matches = FALSE;
11710     if (sdp->choice == Seq_descr_pub && sdp->data.ptrvalue != NULL)
11711     {
11712       pdp = (PubdescPtr) sdp->data.ptrvalue;
11713       for (pub = pdp->pub; pub != NULL && ! this_pub_matches; pub = pub->next)
11714       {
11715         this_pub_matches = DoesPubMatchConstraint (pub, epfp->pcp);
11716       }
11717       this_is_submitter_block = PubdescIsSubmitterBlock (pdp);
11718       if ((this_is_submitter_block && ! repl_is_submitter_block)
11719           || (! this_is_submitter_block && repl_is_submitter_block))
11720       {
11721         this_pub_matches = FALSE;
11722       }
11723 
11724       if (this_pub_matches)
11725       {
11726         if (epfp->found_one_pub)
11727         {
11728           epfp->found_conflict = TRUE;
11729         }
11730         else
11731         {
11732           epfp->found_one_pub = TRUE;
11733           epfp->found_any_pubs = TRUE;
11734         }
11735       }
11736     }
11737     sdp = sdp->next;
11738   }
11739 }
11740 
FindPubReplaceConflictsInAnnot(SeqAnnotPtr annot,EditPubFormPtr epfp)11741 static void FindPubReplaceConflictsInAnnot (SeqAnnotPtr annot, EditPubFormPtr epfp)
11742 {
11743   SeqFeatPtr sfp;
11744   Boolean    this_pub_matches;
11745   PubPtr     pub;
11746   PubdescPtr pdp;
11747 
11748   if (annot == NULL || epfp == NULL) return;
11749 
11750   while (annot != NULL && ! epfp->found_conflict)
11751   {
11752     if (annot->type == 1)
11753     {
11754       for (sfp = annot->data; sfp != NULL && ! epfp->found_conflict; sfp = sfp->next)
11755       {
11756         if (sfp->data.choice == SEQFEAT_PUB && sfp->data.value.ptrvalue != NULL)
11757         {
11758           this_pub_matches = FALSE;
11759           pdp = sfp->data.value.ptrvalue;
11760           for (pub = pdp->pub; pub != NULL && ! this_pub_matches; pub = pub->next)
11761           {
11762             this_pub_matches = DoesPubMatchConstraint (pub, epfp->pcp);
11763           }
11764           if (this_pub_matches)
11765           {
11766             if (epfp->found_one_pub)
11767             {
11768               epfp->found_conflict = TRUE;
11769             }
11770             else
11771             {
11772               epfp->found_one_pub = TRUE;
11773               epfp->found_any_pubs = TRUE;
11774             }
11775           }
11776         }
11777       }
11778     }
11779     annot = annot->next;
11780   }
11781 }
11782 
11783 
FindPubReplaceConflictsOnBioseq(BioseqPtr bsp,EditPubFormPtr epfp)11784 static void FindPubReplaceConflictsOnBioseq (BioseqPtr bsp, EditPubFormPtr epfp)
11785 {
11786   if (bsp == NULL || epfp == NULL) return;
11787 
11788   /* don't need to check if we've found a conflict somewhere else */
11789   if (epfp->found_conflict) return;
11790 
11791   FindPubReplaceConflictsInDescr (bsp->descr, epfp);
11792   FindPubReplaceConflictsInAnnot (bsp->annot, epfp);
11793 }
11794 
11795 static void FindPubReplaceConflictsInSeqEntry (SeqEntryPtr sep, EditPubFormPtr epfp);
11796 
FindPubReplaceConflictsOnBioseqSet(BioseqSetPtr bssp,EditPubFormPtr epfp)11797 static void FindPubReplaceConflictsOnBioseqSet (BioseqSetPtr bssp, EditPubFormPtr epfp)
11798 {
11799   if (bssp == NULL || epfp == NULL) return;
11800 
11801   /* don't need to check if we've found a conflict somewhere else */
11802   if (epfp->found_conflict) return;
11803 
11804   FindPubReplaceConflictsInDescr (bssp->descr, epfp);
11805   FindPubReplaceConflictsInAnnot (bssp->annot, epfp);
11806 
11807   if (!epfp->found_conflict)
11808   {
11809     FindPubReplaceConflictsInSeqEntry (bssp->seq_set, epfp);
11810   }
11811 }
11812 
FindPubReplaceConflictsInSeqEntry(SeqEntryPtr sep,EditPubFormPtr epfp)11813 static void FindPubReplaceConflictsInSeqEntry (SeqEntryPtr sep, EditPubFormPtr epfp)
11814 {
11815   Boolean found_above;
11816 
11817   if (sep == NULL || epfp == NULL) return;
11818 
11819   found_above = epfp->found_one_pub;
11820 
11821   while (sep != NULL)
11822   {
11823     if (IS_Bioseq (sep))
11824     {
11825       FindPubReplaceConflictsOnBioseq ((BioseqPtr) sep->data.ptrvalue, epfp);
11826     }
11827     else if (IS_Bioseq_set (sep))
11828     {
11829       FindPubReplaceConflictsOnBioseqSet ((BioseqSetPtr) sep->data.ptrvalue, epfp);
11830     }
11831     sep = sep->next;
11832     epfp->found_one_pub = found_above;
11833   }
11834 
11835 }
11836 
MakeNewSubmitterBlock(PubdescPtr old_pdp,PubdescPtr repl_pdp)11837 static PubdescPtr MakeNewSubmitterBlock (PubdescPtr old_pdp, PubdescPtr repl_pdp)
11838 {
11839   PubPtr     pub;
11840   CitSubPtr  csp = NULL;
11841   DatePtr    sub_date;
11842   PubdescPtr new_pdp;
11843 
11844   if (old_pdp == NULL || repl_pdp == NULL || !PubdescIsSubmitterBlock (repl_pdp))
11845   {
11846     return NULL;
11847   }
11848   for (pub = old_pdp->pub; pub != NULL && csp == NULL; pub = pub->next)
11849   {
11850     if (pub->choice == PUB_Sub)
11851     {
11852       csp = (CitSubPtr) pub->data.ptrvalue;
11853     }
11854   }
11855   if (csp == NULL) return NULL;
11856   sub_date = csp->date;
11857 
11858   new_pdp = AsnIoMemCopy ((Pointer) repl_pdp,
11859                           (AsnReadFunc) PubdescAsnRead,
11860                           (AsnWriteFunc) PubdescAsnWrite);
11861 
11862   for (pub = new_pdp->pub; pub != NULL; pub = pub->next)
11863   {
11864     if (pub->choice == PUB_Sub)
11865     {
11866       csp = (CitSubPtr) pub->data.ptrvalue;
11867       csp->date = DateFree (csp->date);
11868       csp->date = AsnIoMemCopy ((Pointer)sub_date,
11869                                 (AsnReadFunc) DateAsnRead,
11870                                 (AsnWriteFunc) DateAsnWrite);
11871     }
11872   }
11873   return new_pdp;
11874 }
11875 
ReplacePubFeature(SeqFeatPtr sfp,Pointer userdata)11876 static void ReplacePubFeature (SeqFeatPtr sfp, Pointer userdata)
11877 {
11878   EditPubFormPtr    epfp;
11879   PubPtr     pub;
11880   PubdescPtr pdp, new_pdp;
11881   Boolean    this_pub_matches = FALSE;
11882   Boolean    this_pub_is_submitter_block = FALSE;
11883   Boolean    replace_pub_is_submitter_block = FALSE;
11884 
11885 
11886   if (sfp == NULL || sfp->data.choice != SEQFEAT_PUB || userdata == NULL)
11887   {
11888     return;
11889   }
11890   epfp = (EditPubFormPtr) userdata;
11891 
11892   pdp = sfp->data.value.ptrvalue;
11893 
11894   this_pub_is_submitter_block = PubdescIsSubmitterBlock (pdp);
11895   replace_pub_is_submitter_block = PubdescIsSubmitterBlock (epfp->replacement_pdp);
11896   if ((this_pub_is_submitter_block && ! replace_pub_is_submitter_block)
11897       || (!this_pub_is_submitter_block && replace_pub_is_submitter_block))
11898   {
11899     return;
11900   }
11901 
11902   for (pub = pdp->pub; pub != NULL && ! this_pub_matches; pub = pub->next)
11903   {
11904     this_pub_matches = DoesPubMatchConstraint (pub, epfp->pcp);
11905   }
11906 
11907   if (this_pub_matches)
11908   {
11909     if (this_pub_is_submitter_block)
11910     {
11911       new_pdp = MakeNewSubmitterBlock (pdp, epfp->replacement_pdp);
11912     }
11913     else
11914     {
11915       new_pdp = AsnIoMemCopy ((Pointer) epfp->replacement_pdp,
11916                               (AsnReadFunc) PubdescAsnRead,
11917                               (AsnWriteFunc) PubdescAsnWrite);
11918     }
11919 
11920     pdp = PubdescFree (pdp);
11921     sfp->data.value.ptrvalue = new_pdp;
11922   }
11923 }
11924 
ReplacePubDescriptor(SeqDescrPtr sdp,Pointer userdata)11925 static void ReplacePubDescriptor (SeqDescrPtr sdp, Pointer userdata)
11926 {
11927   EditPubFormPtr    epfp;
11928   PubPtr     pub;
11929   PubdescPtr pdp, new_pdp;
11930   Boolean    this_pub_matches = FALSE;
11931   Boolean    this_pub_is_submitter_block = FALSE;
11932   Boolean    replace_pub_is_submitter_block = FALSE;
11933 
11934   if (sdp == NULL || userdata == NULL || sdp->choice != Seq_descr_pub)
11935   {
11936     return;
11937   }
11938   epfp = (EditPubFormPtr) userdata;
11939 
11940   pdp = sdp->data.ptrvalue;
11941 
11942   this_pub_is_submitter_block = PubdescIsSubmitterBlock (pdp);
11943   replace_pub_is_submitter_block = PubdescIsSubmitterBlock (epfp->replacement_pdp);
11944   if ((this_pub_is_submitter_block && ! replace_pub_is_submitter_block)
11945       || (!this_pub_is_submitter_block && replace_pub_is_submitter_block))
11946   {
11947     return;
11948   }
11949 
11950   for (pub = pdp->pub; pub != NULL && ! this_pub_matches; pub = pub->next)
11951   {
11952     this_pub_matches = DoesPubMatchConstraint (pub, epfp->pcp);
11953   }
11954 
11955   if (this_pub_matches)
11956   {
11957     if (this_pub_is_submitter_block)
11958     {
11959       new_pdp = MakeNewSubmitterBlock (pdp, epfp->replacement_pdp);
11960     }
11961     else
11962     {
11963       new_pdp = AsnIoMemCopy ((Pointer) epfp->replacement_pdp,
11964                               (AsnReadFunc) PubdescAsnRead,
11965                               (AsnWriteFunc) PubdescAsnWrite);
11966     }
11967 
11968     pdp = PubdescFree (pdp);
11969     sdp->data.ptrvalue = new_pdp;
11970   }
11971 }
11972 
ReplacePubsWithSelectedPubsByConstraint(SeqEntryPtr sep,EditPubFormPtr epfp)11973 static Boolean ReplacePubsWithSelectedPubsByConstraint (SeqEntryPtr sep, EditPubFormPtr epfp)
11974 {
11975   MsgAnswer  ans = ANS_YES;
11976   Boolean    rval = FALSE;
11977   PubdescPtr pdp;
11978 
11979   if (sep == NULL || epfp == NULL) return FALSE;
11980 
11981   pdp = FindFirstSelectedPub ();
11982   if (pdp == NULL)
11983   {
11984     Message (MSG_ERROR, "No publication selected!");
11985     return FALSE;
11986   }
11987   epfp->replacement_pdp = AsnIoMemCopy ((Pointer) pdp,
11988                                         (AsnReadFunc) PubdescAsnRead,
11989                                         (AsnWriteFunc) PubdescAsnWrite);
11990 
11991   epfp->found_one_pub = FALSE;
11992   epfp->found_conflict = FALSE;
11993   FindPubReplaceConflictsInSeqEntry (sep, epfp);
11994   if (epfp->found_conflict)
11995   {
11996     ans = Message (MSG_YN, "You will be replacing more than one publication "
11997            "per sequence - is this OK?  (Select No to go back and edit constraints)");
11998   }
11999   else if (!epfp->found_any_pubs)
12000   {
12001     Message (MSG_ERROR, "There are no publications matching your constraint.");
12002     ans = ANS_NO;
12003   }
12004   if (ans == ANS_YES)
12005   {
12006     rval = TRUE;
12007     VisitFeaturesInSep (sep, epfp, ReplacePubFeature);
12008     VisitDescriptorsInSep (sep, epfp, ReplacePubDescriptor);
12009   }
12010 
12011   epfp->replacement_pdp = PubdescFree (epfp->replacement_pdp);
12012   return rval;
12013 }
12014 
12015 
12016 typedef Int4 (LIBCALLBACK *GetItemTextLength) (Pointer userdata);
12017 
12018 typedef void (LIBCALLBACK *PrintItemToBuffer) (CharPtr cp, Pointer userdata);
12019 
12020 typedef struct doublelist
12021 {
12022   DIALOG_MESSAGE_BLOCK
12023   DoC                  list1_ctrl;
12024   DoC                  list2_ctrl;
12025   ButtoN               to_button;
12026   ButtoN               from_button;
12027   ButtoN               to_all_button;
12028   ButtoN               from_all_button;
12029   ValNodePtr           list1;
12030   ValNodePtr           list2;
12031   BoolPtr              list1_clicked;
12032   BoolPtr              list2_clicked;
12033   Int4                 num_total;
12034   GetItemTextLength    getlenproc;
12035   PrintItemToBuffer    printitemproc;
12036   ColData              col;
12037   ParData              par;
12038   Nlm_ChangeNotifyProc change_notify;
12039   Pointer              change_userdata;
12040 } DoubleListData, PNTR DoubleListPtr;
12041 
AllLinePrtProc(DoC d,Int2 item,Pointer ptr)12042 static CharPtr AllLinePrtProc (DoC d, Int2 item, Pointer ptr)
12043 
12044 {
12045   CharPtr  tmp;
12046 
12047   if (ptr != NULL) {
12048     tmp = (CharPtr) ptr;
12049     return StringSave (tmp);
12050   } else {
12051     return NULL;
12052   }
12053 }
12054 
GetDoubleListTextList(ValNodePtr item_list,DoubleListPtr dlp)12055 static CharPtr GetDoubleListTextList (ValNodePtr item_list, DoubleListPtr dlp)
12056 {
12057   Int4       text_len = 0;
12058   ValNodePtr vnp;
12059   CharPtr    text_list, cp;
12060 
12061   if (dlp == NULL || dlp->getlenproc == NULL || dlp->printitemproc == NULL)
12062   {
12063     return NULL;
12064   }
12065   for (vnp = item_list; vnp != NULL; vnp = vnp->next)
12066   {
12067     text_len += dlp->getlenproc (vnp->data.ptrvalue);
12068   }
12069   if (text_len == 0) return NULL;
12070   text_list = (CharPtr) MemNew (text_len * sizeof (Char));
12071   if (text_list == NULL) return NULL;
12072   cp = text_list;
12073   for (vnp = item_list; vnp != NULL; vnp = vnp->next)
12074   {
12075     dlp->printitemproc (cp, vnp->data.ptrvalue);
12076     cp += StringLen (cp);
12077   }
12078   return text_list;
12079 }
12080 
ClickList1(DoC d,PoinT pt)12081 static void ClickList1 (DoC d, PoinT pt)
12082 
12083 {
12084   DoubleListPtr  dlp;
12085   Int2           item;
12086   Int2           row;
12087 
12088   dlp = (DoubleListPtr) GetObjectExtra (d);
12089   if (dlp != NULL) {
12090     MapDocPoint (d, pt, &item, &row, NULL, NULL);
12091     if (item > 0 && row > 0) {
12092       dlp->list1_clicked [row - 1] = ! dlp->list1_clicked [row - 1];
12093       InvalDocRows (d, 1, row, row);
12094     }
12095   }
12096 }
12097 
ClickList2(DoC d,PoinT pt)12098 static void ClickList2 (DoC d, PoinT pt)
12099 
12100 {
12101   DoubleListPtr  dlp;
12102   Int2           item;
12103   Int2           row;
12104 
12105   dlp = (DoubleListPtr) GetObjectExtra (d);
12106   if (dlp != NULL) {
12107     MapDocPoint (d, pt, &item, &row, NULL, NULL);
12108     if (item > 0 && row > 0) {
12109       dlp->list2_clicked [row - 1] = ! dlp->list2_clicked [row - 1];
12110       InvalDocRows (d, 1, row, row);
12111     }
12112   }
12113 }
12114 
12115 
ReleaseDoubleListItem(DoC d,PoinT pt)12116 static void ReleaseDoubleListItem (DoC d, PoinT pt)
12117 
12118 {
12119   DoubleListPtr  dlp;
12120   Int2           item;
12121   Int2           row;
12122 
12123   dlp = (DoubleListPtr) GetObjectExtra (d);
12124   if (dlp != NULL) {
12125     MapDocPoint (d, pt, &item, &row, NULL, NULL);
12126     if (item > 0 && row > 0) {
12127       ResetClip ();
12128     }
12129   }
12130 }
12131 
HighlightList1(DoC d,Int2 item,Int2 row,Int2 col)12132 static Boolean HighlightList1 (DoC d, Int2 item, Int2 row, Int2 col)
12133 
12134 {
12135   DoubleListPtr  dlp;
12136 
12137   dlp = (DoubleListPtr) GetObjectExtra (d);
12138   if (dlp != NULL) {
12139     return dlp->list1_clicked [row - 1];
12140   } else {
12141     return FALSE;
12142   }
12143 }
12144 
HighlightList2(DoC d,Int2 item,Int2 row,Int2 col)12145 static Boolean HighlightList2 (DoC d, Int2 item, Int2 row, Int2 col)
12146 
12147 {
12148   DoubleListPtr  dlp;
12149 
12150   dlp = (DoubleListPtr) GetObjectExtra (d);
12151   if (dlp != NULL) {
12152     return dlp->list2_clicked [row - 1];
12153   } else {
12154     return FALSE;
12155   }
12156 }
12157 
RedrawDoubleListDialog(DoubleListPtr dlp)12158 static void RedrawDoubleListDialog (DoubleListPtr dlp)
12159 {
12160   CharPtr new_text;
12161   Int4    idx;
12162   RecT    r;
12163   BaR     sb;
12164   Int4    orig_pos, barmax;
12165 
12166   if (dlp == NULL) return;
12167 
12168   sb = GetSlateVScrollBar ((SlatE) dlp->list1_ctrl);
12169   orig_pos = GetBarValue (sb);
12170 
12171 	Reset(dlp->list1_ctrl);
12172   SetDocAutoAdjust (dlp->list1_ctrl, FALSE);
12173   new_text = GetDoubleListTextList (dlp->list1, dlp);
12174   AppendItem (dlp->list1_ctrl, AllLinePrtProc, new_text, FALSE, ValNodeLen (dlp->list1),
12175                 &(dlp->par), &(dlp->col), programFont);
12176   SetDocAutoAdjust (dlp->list1_ctrl, TRUE);
12177   SetDocProcs (dlp->list1_ctrl, ClickList1, NULL, ReleaseDoubleListItem, NULL);
12178   SetDocShade (dlp->list1_ctrl, NULL, NULL, HighlightList1, NULL);
12179   AdjustDocScroll (dlp->list1_ctrl);
12180 
12181   barmax = GetBarMax (sb);
12182   if (barmax < orig_pos)
12183   {
12184     orig_pos = barmax;
12185   }
12186   SetBarValue (sb, orig_pos);
12187 
12188   sb = GetSlateVScrollBar ((SlatE) dlp->list2_ctrl);
12189   orig_pos = GetBarValue (sb);
12190 	Reset(dlp->list2_ctrl);
12191   SetDocAutoAdjust (dlp->list2_ctrl, FALSE);
12192   new_text = GetDoubleListTextList (dlp->list2, dlp);
12193   AppendItem (dlp->list2_ctrl, AllLinePrtProc, new_text, FALSE, ValNodeLen (dlp->list2),
12194                 &(dlp->par), &(dlp->col), programFont);
12195   SetDocAutoAdjust (dlp->list2_ctrl, TRUE);
12196   SetDocProcs (dlp->list2_ctrl, ClickList2, NULL, ReleaseDoubleListItem, NULL);
12197   SetDocShade (dlp->list2_ctrl, NULL, NULL, HighlightList2, NULL);
12198 
12199   AdjustDocScroll (dlp->list2_ctrl);
12200   barmax = GetBarMax (sb);
12201   if (barmax < orig_pos)
12202   {
12203     orig_pos = barmax;
12204   }
12205   SetBarValue (sb, orig_pos);
12206 
12207   ObjectRect (dlp->list1_ctrl, &r);
12208   InsetRect (&r, -1, -1);
12209   InvalRect (&r);
12210   ObjectRect (dlp->list2_ctrl, &r);
12211   InsetRect (&r, -1, -1);
12212   InvalRect (&r);
12213 
12214 
12215   /* clear selections for both lists */
12216   for (idx = 0; idx < dlp->num_total; idx++)
12217   {
12218     dlp->list1_clicked [idx] = FALSE;
12219     dlp->list2_clicked [idx] = FALSE;
12220   }
12221 }
12222 
MoveToList2(ButtoN b)12223 static void MoveToList2 (ButtoN b)
12224 {
12225   DoubleListPtr  dlp;
12226   ValNodePtr     vnp, prev = NULL, vnp_next;
12227   Int4           idx;
12228 
12229   dlp = (DoubleListPtr) GetObjectExtra (b);
12230   if (dlp != NULL)
12231   {
12232     for (vnp = dlp->list1, idx = 0;
12233          vnp != NULL && idx < dlp->num_total;
12234          vnp = vnp_next, idx++)
12235     {
12236       vnp_next = vnp->next;
12237       if (dlp->list1_clicked [idx])
12238       {
12239         /* add item to list2 */
12240         ValNodeAddPointer (&dlp->list2, vnp->choice, vnp->data.ptrvalue);
12241 
12242         /* remove item from list1 */
12243         vnp->data.ptrvalue = NULL;
12244         if (prev == NULL)
12245         {
12246           dlp->list1 = vnp->next;
12247         }
12248         else
12249         {
12250           prev->next = vnp->next;
12251         }
12252         vnp->next = NULL;
12253         ValNodeFree (vnp);
12254 
12255       }
12256       else
12257       {
12258         prev = vnp;
12259       }
12260     }
12261     /* redraw contents of docpanels */
12262     RedrawDoubleListDialog (dlp);
12263     if (dlp->change_notify != NULL)
12264     {
12265       (dlp->change_notify) (dlp->change_userdata);
12266     }
12267   }
12268 }
12269 
MoveToList1(ButtoN b)12270 static void MoveToList1 (ButtoN b)
12271 {
12272   DoubleListPtr  dlp;
12273   ValNodePtr     vnp, prev = NULL, vnp_next;
12274   Int4           idx;
12275 
12276   dlp = (DoubleListPtr) GetObjectExtra (b);
12277   if (dlp != NULL)
12278   {
12279     for (vnp = dlp->list2, idx = 0;
12280          vnp != NULL && idx < dlp->num_total;
12281          vnp = vnp_next, idx++)
12282     {
12283       vnp_next = vnp->next;
12284       if (dlp->list2_clicked [idx])
12285       {
12286         /* add item to list2 */
12287         ValNodeAddPointer (&dlp->list1, vnp->choice, vnp->data.ptrvalue);
12288 
12289         /* remove item from list1 */
12290         vnp->data.ptrvalue = NULL;
12291         if (prev == NULL)
12292         {
12293           dlp->list2 = vnp->next;
12294         }
12295         else
12296         {
12297           prev->next = vnp->next;
12298         }
12299         vnp->next = NULL;
12300         ValNodeFree (vnp);
12301 
12302       }
12303       else
12304       {
12305         prev = vnp;
12306       }
12307     }
12308     /* redraw contents of docpanels */
12309     RedrawDoubleListDialog (dlp);
12310 
12311     if (dlp->change_notify != NULL)
12312     {
12313       (dlp->change_notify) (dlp->change_userdata);
12314     }
12315   }
12316 }
12317 
MoveAllToList2(ButtoN b)12318 static void MoveAllToList2 (ButtoN b)
12319 {
12320   DoubleListPtr  dlp;
12321 
12322   dlp = (DoubleListPtr) GetObjectExtra (b);
12323   if (dlp == NULL)
12324   {
12325     return;
12326   }
12327 
12328   ValNodeLink (&(dlp->list2), dlp->list1);
12329   dlp->list1 = NULL;
12330 
12331   /* redraw contents of docpanels */
12332   RedrawDoubleListDialog (dlp);
12333   if (dlp->change_notify != NULL)
12334   {
12335     (dlp->change_notify) (dlp->change_userdata);
12336   }
12337 }
12338 
MoveAllToList1(ButtoN b)12339 static void MoveAllToList1 (ButtoN b)
12340 {
12341   DoubleListPtr  dlp;
12342 
12343   dlp = (DoubleListPtr) GetObjectExtra (b);
12344   if (dlp == NULL)
12345   {
12346     return;
12347   }
12348 
12349   ValNodeLink (&(dlp->list1), dlp->list2);
12350   dlp->list2 = NULL;
12351 
12352   /* redraw contents of docpanels */
12353   RedrawDoubleListDialog (dlp);
12354   if (dlp->change_notify != NULL)
12355   {
12356     (dlp->change_notify) (dlp->change_userdata);
12357   }
12358 }
12359 
ListPairToDoubleListDialog(DialoG d,Pointer data)12360 static void ListPairToDoubleListDialog (DialoG d, Pointer data)
12361 {
12362   DoubleListPtr dlp;
12363   ValNodePtr    list_pair;
12364 
12365 
12366   dlp = (DoubleListPtr) GetObjectExtra (d);
12367   if (dlp == NULL)
12368   {
12369     return;
12370   }
12371 	Reset(dlp->list1_ctrl);
12372 	Reset(dlp->list2_ctrl);
12373 	dlp->list1 = NULL;
12374 	dlp->list2 = NULL;
12375 
12376   list_pair = (ValNodePtr) data;
12377   if (list_pair != NULL)
12378   {
12379     dlp->list1 = list_pair->data.ptrvalue;
12380     if (list_pair->next != NULL)
12381     {
12382       dlp->list2 = list_pair->next->data.ptrvalue;
12383     }
12384   }
12385 
12386   /* set up clicked lists */
12387   dlp->list1_clicked = MemFree (dlp->list1_clicked);
12388   dlp->list2_clicked = MemFree (dlp->list2_clicked);
12389   dlp->num_total = ValNodeLen (dlp->list1) + ValNodeLen (dlp->list2);
12390   dlp->list1_clicked = (BoolPtr) MemNew (dlp->num_total * sizeof (Boolean));
12391   dlp->list2_clicked = (BoolPtr) MemNew (dlp->num_total * sizeof (Boolean));
12392 
12393 
12394 
12395   RedrawDoubleListDialog (dlp);
12396   if (dlp->change_notify != NULL)
12397   {
12398     (dlp->change_notify) (dlp->change_userdata);
12399   }
12400 }
12401 
DoubleListDialogToListPair(DialoG d)12402 static Pointer DoubleListDialogToListPair (DialoG d)
12403 {
12404   DoubleListPtr dlp;
12405   ValNodePtr    list_pair = NULL;
12406   ValNodePtr    vnp, list_tmp = NULL;
12407 
12408   dlp = (DoubleListPtr) GetObjectExtra (d);
12409   if (dlp == NULL)
12410   {
12411     return NULL;
12412   }
12413 
12414   list_tmp = NULL;
12415   for (vnp = dlp->list1; vnp != NULL; vnp = vnp->next) {
12416     ValNodeAddPointer (&list_tmp, vnp->choice, vnp->data.ptrvalue);
12417   }
12418   ValNodeAddPointer (&list_pair, 0, list_tmp);
12419 
12420   list_tmp = NULL;
12421   for (vnp = dlp->list2; vnp != NULL; vnp = vnp->next) {
12422     ValNodeAddPointer (&list_tmp, vnp->choice, vnp->data.ptrvalue);
12423   }
12424   ValNodeAddPointer (&list_pair, 0, list_tmp);
12425   return list_pair;
12426 }
12427 
CleanupDoubleListDialog(GraphiC g,VoidPtr data)12428 static void CleanupDoubleListDialog (GraphiC g, VoidPtr data)
12429 {
12430   DoubleListPtr dlp;
12431 
12432   dlp = (DoubleListPtr) data;
12433   if (dlp != NULL)
12434   {
12435     dlp->list1 = ValNodeFree (dlp->list1);
12436     dlp->list2 = ValNodeFree (dlp->list2);
12437   }
12438   StdCleanupExtraProc (g, data);
12439 }
12440 
12441 
12442 static DialoG
DoubleListDialog(GrouP parent,CharPtr list1_title,CharPtr list2_title,GetItemTextLength getlenproc,PrintItemToBuffer printitemproc,Nlm_ChangeNotifyProc change_notify,Pointer change_userdata)12443 DoubleListDialog
12444 (GrouP              parent,
12445  CharPtr            list1_title,
12446  CharPtr            list2_title,
12447  GetItemTextLength  getlenproc,
12448  PrintItemToBuffer  printitemproc,
12449  Nlm_ChangeNotifyProc     change_notify,
12450  Pointer                  change_userdata)
12451 {
12452   DoubleListPtr dlp;
12453   GrouP         p, k;
12454   RecT          r;
12455   Int2          height = LineHeight ();
12456 
12457   dlp = (DoubleListPtr) MemNew (sizeof (DoubleListData));
12458   if (dlp == NULL)
12459   {
12460     return NULL;
12461   }
12462 
12463   dlp->getlenproc = getlenproc;
12464   dlp->printitemproc = printitemproc;
12465   dlp->change_notify = change_notify;
12466   dlp->change_userdata = change_userdata;
12467 
12468   p = HiddenGroup (parent, 3, 0, NULL);
12469   SetGroupSpacing (p, 10, 10);
12470   SetObjectExtra (p, dlp, CleanupDoubleListDialog);
12471 
12472   dlp->dialog = (DialoG) p;
12473   dlp->todialog = ListPairToDoubleListDialog;
12474   dlp->fromdialog = DoubleListDialogToListPair;
12475 
12476   /* top row - labels */
12477   StaticPrompt (p, list1_title, 0, dialogTextHeight, programFont, 'c');
12478   StaticPrompt (p, "", 0, dialogTextHeight, programFont, 'c');
12479   StaticPrompt (p, list2_title, 0, dialogTextHeight, programFont, 'c');
12480   /* panel 1 */
12481   dlp->list1_ctrl = DocumentPanel (p, stdCharWidth * 25, height * 7);
12482   SetObjectExtra (dlp->list1_ctrl, dlp, NULL);
12483   /* movement buttons */
12484   k = HiddenGroup (p, 0, 4, NULL);
12485   dlp->to_button = PushButton (k, "->", MoveToList2);
12486   SetObjectExtra (dlp->to_button, dlp, NULL);
12487   dlp->to_all_button = PushButton (k, "All->", MoveAllToList2);
12488   SetObjectExtra (dlp->to_all_button, dlp, NULL);
12489 
12490   dlp->from_button = PushButton (k, "<-", MoveToList1);
12491   SetObjectExtra (dlp->from_button, dlp, NULL);
12492   dlp->from_all_button = PushButton (k, "<-All", MoveAllToList1);
12493   SetObjectExtra (dlp->from_all_button, dlp, NULL);
12494   /* panel 2 */
12495   dlp->list2_ctrl = DocumentPanel (p, stdCharWidth * 25, height * 7);
12496   SetObjectExtra (dlp->list2_ctrl, dlp, NULL);
12497 
12498   ObjectRect (dlp->list1_ctrl, &r);
12499   dlp->col.pixWidth  = r.right - r.left;
12500   dlp->col.pixInset  = 0;
12501   dlp->col.charWidth = 80;
12502   dlp->col.charInset = 0;
12503   dlp->col.font      = NULL;
12504   dlp->col.just      = 'l';
12505   dlp->col.wrap      = FALSE;
12506   dlp->col.bar       = FALSE;
12507   dlp->col.underline = FALSE;
12508   dlp->col.left = FALSE;
12509   dlp->col.last = TRUE;
12510 
12511   dlp->par.openSpace    = FALSE;
12512   dlp->par.keepWithNext = FALSE;
12513   dlp->par.keepTogether = FALSE;
12514   dlp->par.newPage      = FALSE;
12515   dlp->par.tabStops     = FALSE;
12516   dlp->par.minLines     = 0;
12517   dlp->par.minHeight    = 0;
12518 
12519   return (DialoG) p;
12520 }
12521 
12522 typedef struct adjustlistpair
12523 {
12524   DialoG                list_pair_dlg;
12525   ButtoN                accept_btn;
12526   Boolean               none_in_1_ok;
12527   Boolean               none_in_2_ok;
12528 } AdjustListPairData, PNTR AdjustListPairPtr;
12529 
EnableAdjustListPairAccept(Pointer data)12530 static void EnableAdjustListPairAccept (Pointer data)
12531 {
12532   AdjustListPairPtr alpp;
12533   ValNodePtr        list_pair, vnp;
12534 
12535   alpp = (AdjustListPairPtr) data;
12536   if (alpp == NULL)
12537   {
12538     return;
12539   }
12540   if (alpp->none_in_1_ok && alpp->none_in_2_ok)
12541   {
12542     Enable (alpp->accept_btn);
12543     return;
12544   }
12545 
12546   list_pair = DialogToPointer (alpp->list_pair_dlg);
12547   if (list_pair == NULL
12548       || (!alpp->none_in_1_ok && list_pair->data.ptrvalue == NULL)
12549       || (!alpp->none_in_2_ok
12550            && (list_pair->next == NULL
12551                || list_pair->next->data.ptrvalue == NULL)))
12552   {
12553     Disable (alpp->accept_btn);
12554   }
12555   else
12556   {
12557     Enable (alpp->accept_btn);
12558   }
12559   for (vnp = list_pair; vnp != NULL; vnp = vnp->next) {
12560     vnp->data.ptrvalue = ValNodeFree (vnp->data.ptrvalue);
12561   }
12562   list_pair = ValNodeFree (list_pair);
12563 }
12564 
12565 static Boolean
AdjustListPair(ValNodePtr PNTR list1,ValNodePtr PNTR list2,CharPtr list1_title,CharPtr list2_title,GetItemTextLength getlenproc,PrintItemToBuffer printitemproc,Boolean none_in_1_ok,Boolean none_in_2_ok)12566 AdjustListPair
12567 (ValNodePtr PNTR list1,
12568  ValNodePtr PNTR list2,
12569  CharPtr            list1_title,
12570  CharPtr            list2_title,
12571  GetItemTextLength  getlenproc,
12572  PrintItemToBuffer  printitemproc,
12573  Boolean            none_in_1_ok,
12574  Boolean            none_in_2_ok)
12575 {
12576   WindoW                w;
12577   GrouP                 h, c;
12578   ButtoN                b;
12579   ModalAcceptCancelData acd;
12580   AdjustListPairData    alpd;
12581   ValNodePtr            list_pair = NULL;
12582   Boolean               rval = FALSE;
12583 
12584   if (list1 == NULL || list2 == NULL) return FALSE;
12585 
12586   w = ModalWindow (-50, -33, -10, -10, NULL);
12587   h = HiddenGroup (w, -1, 0, NULL);
12588   SetGroupSpacing (h, 10, 10);
12589 
12590   alpd.none_in_1_ok = none_in_1_ok;
12591   alpd.none_in_2_ok = none_in_2_ok;
12592 
12593   alpd.list_pair_dlg = DoubleListDialog (h, list1_title, list2_title,
12594                                     getlenproc, printitemproc,
12595                                     EnableAdjustListPairAccept,
12596                                     &alpd);
12597 
12598   c = HiddenGroup (h, 4, 0, NULL);
12599   alpd.accept_btn = PushButton (c, "Accept", ModalAcceptButton);
12600   SetObjectExtra (alpd.accept_btn, &acd, NULL);
12601   b = PushButton (c, "Cancel", ModalCancelButton);
12602   SetObjectExtra (b, &acd, NULL);
12603 
12604   AlignObjects (ALIGN_CENTER, (HANDLE) alpd.list_pair_dlg, (HANDLE) c, NULL);
12605 
12606   acd.accepted = FALSE;
12607   acd.cancelled = FALSE;
12608 
12609   ValNodeAddPointer (&list_pair, 0, *list1);
12610   ValNodeAddPointer (&list_pair, 0, *list2);
12611   *list1 = NULL;
12612   *list2 = NULL;
12613   PointerToDialog (alpd.list_pair_dlg, list_pair);
12614   list_pair = ValNodeFree (list_pair);
12615 
12616   RealizeWindow (w);
12617   Show (w);
12618   Update ();
12619 
12620   while (!acd.accepted && ! acd.cancelled)
12621   {
12622     ProcessExternalEvent ();
12623     Update ();
12624   }
12625   ProcessAnEvent ();
12626   if (acd.accepted)
12627   {
12628     list_pair = DialogToPointer (alpd.list_pair_dlg);
12629     if (list_pair != NULL && list_pair->next != NULL)
12630     {
12631       *list1 = list_pair->data.ptrvalue;
12632       *list2 = list_pair->next->data.ptrvalue;
12633       rval = TRUE;
12634     }
12635     list_pair = ValNodeFree (list_pair);
12636   }
12637   Remove (w);
12638   return rval;
12639 }
12640 
GetAuthorPrintLen(Pointer userdata)12641 static Int4 LIBCALLBACK GetAuthorPrintLen (Pointer userdata)
12642 {
12643   Int4       text_len = 0;
12644   NameStdPtr pName;
12645   AuthorPtr  ap;
12646 
12647   ap = (AuthorPtr) userdata;
12648   if (ap == NULL || ap->name == NULL || ap->name->data == NULL) return 0;
12649 
12650   if (ap->name->choice == 2)
12651   {
12652     pName = (NameStdPtr) ap->name->data;
12653     if (!StringHasNoText (pName->names[0]))
12654     {
12655       text_len += StringLen (pName->names [0]) + 3;
12656     }
12657     if (!StringHasNoText (pName->names[4]))
12658     {
12659       text_len += StringLen (pName->names[4]) + 2;
12660     }
12661   }
12662   else if (ap->name->choice == 4 || ap->name->choice == 5)
12663   {
12664     text_len = StringLen (ap->name->data) + 2;
12665   }
12666   return text_len;
12667 }
12668 
PrintAuthor(CharPtr cp,Pointer userdata)12669 static void LIBCALLBACK PrintAuthor (CharPtr cp, Pointer userdata)
12670 {
12671   NameStdPtr pName;
12672   AuthorPtr  ap;
12673 
12674   ap = (AuthorPtr) userdata;
12675   if (ap == NULL || ap->name == NULL || ap->name->data == NULL || cp == NULL) return;
12676 
12677   if (ap->name->choice == 2)
12678   {
12679     pName = (NameStdPtr) ap->name->data;
12680     if (!StringHasNoText (pName->names[0]))
12681     {
12682       StringCat (cp, pName->names[0]);
12683       if (!StringHasNoText (pName->names[4]))
12684       {
12685         StringCat (cp, ", ");
12686       }
12687     }
12688     if (!StringHasNoText (pName->names[4]))
12689     {
12690       StringCat (cp, pName->names[4]);
12691     }
12692   }
12693   else if (ap->name->choice == 4 || ap->name->choice == 5)
12694   {
12695     StringCat (cp, ap->name->data);
12696   }
12697   StringCat (cp, "\n");
12698 }
12699 
12700 #define PUB_EDIT_TYPE_REPLACE_SECTION      1
12701 #define PUB_EDIT_TYPE_REPLACE_PUB          2
12702 #define PUB_EDIT_TYPE_REPLACE_SINGLE_FIELD 3
12703 #define PUB_EDIT_TYPE_MERGE_AUTHOR_LISTS   4
12704 #define MAX_PUB_EDIT_TYPE 4
12705 
ChangeAuthorOrder(EditPubFormPtr epfp)12706 static Boolean ChangeAuthorOrder (EditPubFormPtr epfp)
12707 {
12708   ValNodePtr     list1 = NULL, list2 = NULL, tmp_list = NULL, vnp;
12709   AuthorPtr      ap;
12710   Boolean        rval;
12711 
12712   if (epfp == NULL || epfp->edit_type != PUB_EDIT_TYPE_MERGE_AUTHOR_LISTS)
12713   {
12714     return FALSE;
12715   }
12716 
12717   if (epfp->names_list == NULL || epfp->names_list->next == NULL)
12718   {
12719     return TRUE;
12720   }
12721 
12722   /* create temporary copy of list */
12723   for (vnp = epfp->names_list; vnp != NULL; vnp = vnp->next)
12724   {
12725     ap = AsnIoMemCopy (vnp->data.ptrvalue,
12726                     (AsnReadFunc) AuthorAsnRead,
12727                     (AsnWriteFunc) AuthorAsnWrite);
12728     if (ap != NULL)
12729     {
12730       ValNodeAddPointer (&(list1), vnp->choice, ap);
12731     }
12732   }
12733 
12734   rval = AdjustListPair (&list1, &list2, "Available Authors", "Final List",
12735                       GetAuthorPrintLen, PrintAuthor, TRUE, FALSE);
12736   if (rval)
12737   {
12738     /* now change author order */
12739     tmp_list = epfp->names_list;
12740     epfp->names_list = list2;
12741     list2 = tmp_list;
12742   }
12743 
12744   /* free lists */
12745   for (vnp = list1; vnp != NULL; vnp = vnp->next)
12746   {
12747     vnp->data.ptrvalue = AuthorFree (vnp->data.ptrvalue);
12748   }
12749   list1 = ValNodeFree (list1);
12750   for (vnp = list2; vnp != NULL; vnp = vnp->next)
12751   {
12752     vnp->data.ptrvalue = AuthorFree (vnp->data.ptrvalue);
12753   }
12754   list2 = ValNodeFree (list2);
12755 
12756   return rval;
12757 }
12758 
UpdateFeatureCitations(SeqFeatPtr sfp,Pointer userdata)12759 static void UpdateFeatureCitations (SeqFeatPtr sfp, Pointer userdata)
12760 {
12761   AffectedPubPairPtr appp;
12762   ValNodePtr cit_vnp, prev_cit, next_cit, pub_vnp, pub_list;
12763   ValNodePtr new_cit;
12764   ValNodePtr pubset;
12765   Boolean    found_match;
12766   ValNode    vn;
12767 
12768   if (sfp == NULL || sfp->cit == NULL
12769       || sfp->cit->choice != 1 || sfp->cit->data.ptrvalue == NULL
12770       || userdata == NULL)
12771   {
12772     return;
12773   }
12774 
12775   pubset = sfp->cit;
12776   if (pubset == NULL || pubset->choice != 1)
12777   {
12778     return;
12779   }
12780 
12781   pub_list = (ValNodePtr) userdata;
12782 
12783   prev_cit = NULL;
12784   vn.next = NULL;
12785   for (cit_vnp = pubset->data.ptrvalue; cit_vnp != NULL; cit_vnp = next_cit)
12786   {
12787     next_cit = cit_vnp->next;
12788     found_match = FALSE;
12789     for (pub_vnp = pub_list;
12790          pub_vnp != NULL && !found_match;
12791          pub_vnp = pub_vnp->next)
12792     {
12793       appp = (AffectedPubPairPtr) pub_vnp->data.ptrvalue;
12794       if (appp == NULL || appp->orig == NULL)
12795       {
12796         continue;
12797       }
12798       vn.choice = PUB_Equiv;
12799       vn.data.ptrvalue = appp->orig->pub;
12800       if (PubLabelMatch (cit_vnp, &vn) == 0)
12801       {
12802         found_match = TRUE;
12803       }
12804     }
12805     if (appp != NULL && found_match)
12806     {
12807       /* create a temporary PUB_Equiv to use for minimizing */
12808       vn.choice = PUB_Equiv;
12809       vn.data.ptrvalue = appp->curr->pub;
12810       new_cit = MinimizePub (&vn);
12811 
12812       /* insert new_cit into list */
12813       new_cit->next = cit_vnp->next;
12814       cit_vnp->next = NULL;
12815       cit_vnp = PubFree (cit_vnp);
12816 
12817       if (prev_cit == NULL)
12818       {
12819         sfp->cit->data.ptrvalue = new_cit;
12820       }
12821       else
12822       {
12823         prev_cit->next = new_cit;
12824       }
12825       cit_vnp = new_cit;
12826     }
12827     prev_cit = cit_vnp;
12828   }
12829 }
12830 
DoEditPubs(ButtoN b)12831 static void DoEditPubs (ButtoN b)
12832 {
12833   SeqEntryPtr        sep;
12834   EditPubFormPtr     epfp;
12835   PubPtr             pub;
12836   AuthListPtr        alp;
12837   Int4Ptr            retval;
12838 
12839   epfp = (EditPubFormPtr) GetObjectExtra (b);
12840   if (epfp == NULL) return;
12841 
12842   sep = GetTopSeqEntryForEntityID (epfp->input_entityID);
12843   if (sep == NULL) return;
12844 
12845   epfp->pcp = DialogToPointer (epfp->pub_constraint_dlg);
12846 
12847   switch (epfp->edit_type)
12848   {
12849     case PUB_EDIT_TYPE_REPLACE_SINGLE_FIELD:
12850       retval = DialogToPointer (epfp->field_to_set_dlg);
12851       if (retval == NULL)
12852       {
12853         return;
12854       }
12855       else
12856       {
12857         epfp->field_to_set = *retval;
12858         retval = MemFree (retval);
12859       }
12860 
12861       epfp->repl_string = SaveStringFromText (epfp->repl_string_txt);
12862       OperateOnPubByConstraint (sep, epfp, EditPubSingleField);
12863       break;
12864 
12865     case PUB_EDIT_TYPE_REPLACE_SECTION:
12866       epfp->pdp = FindFirstSelectedPub ();
12867       if (epfp->pdp == NULL)
12868       {
12869         Message (MSG_ERROR, "No selected pub!");
12870         epfp->pcp = PubConstraintFree (epfp->pcp);
12871         return;
12872       }
12873 
12874       epfp->alp = AuthListFree (epfp->alp);
12875       if (GetStatus (epfp->replace_author_list))
12876       {
12877         pub = epfp->pdp->pub;
12878         while (epfp->alp == NULL && pub != NULL)
12879         {
12880           epfp->alp = GetAuthorListForPub (pub);
12881           pub = pub->next;
12882         }
12883         /* make a copy, so that if the selected pub matches the contraint, we won't wipe out
12884          * the contents of the master when we free the AuthListPtr for the selected pub
12885          * when we replace it with itself.
12886          */
12887         if (epfp->alp != NULL)
12888         {
12889           epfp->alp = AsnIoMemCopy ((Pointer) epfp->alp,
12890                     (AsnReadFunc) AuthListAsnRead,
12891                     (AsnWriteFunc) AuthListAsnWrite);
12892         }
12893       }
12894 
12895       epfp->title_str = MemFree (epfp->title_str);
12896       if (GetStatus (epfp->replace_title))
12897       {
12898         pub = epfp->pdp->pub;
12899         while (epfp->title_str == NULL && pub != NULL)
12900         {
12901           epfp->title_str = GetPubTitleSample (pub);
12902           pub = pub->next;
12903         }
12904         epfp->title_str = StringSave (epfp->title_str);
12905       }
12906 
12907       epfp->affil = AffilFree (epfp->affil);
12908       if (GetStatus (epfp->replace_affiliation))
12909       {
12910         pub = epfp->pdp->pub;
12911         while (epfp->affil == NULL && pub != NULL)
12912         {
12913           alp = GetAuthorListForPub (pub);
12914           if (alp != NULL && alp->affil != NULL)
12915           {
12916             epfp->affil = AsnIoMemCopy ((Pointer) alp->affil,
12917                         (AsnReadFunc) AffilAsnRead,
12918                         (AsnWriteFunc) AffilAsnWrite);
12919           }
12920           pub = pub->next;
12921         }
12922       }
12923       OperateOnPubByConstraint (sep, epfp, ReplacePubSectByConstraint);
12924 
12925       break;
12926 
12927     case PUB_EDIT_TYPE_MERGE_AUTHOR_LISTS:
12928       /* clear out any old list */
12929       epfp->names_list = FreeAuthorNameList (epfp->names_list);
12930 
12931       /* get the merged list */
12932       OperateOnPubByConstraint (sep, epfp, GetMergedAuthorListByConstraint);
12933 
12934       if (GetValue (epfp->specify_author_order) == 2)
12935       {
12936         if (!ChangeAuthorOrder (epfp))
12937         {
12938           /* cancelled - go back to dialog */
12939           epfp->pcp = PubConstraintFree (epfp->pcp);
12940           return;
12941         }
12942       }
12943 
12944       /* now set the merged list */
12945       OperateOnPubByConstraint (sep, epfp, SetMergedAuthorListByConstraint);
12946       break;
12947     case PUB_EDIT_TYPE_REPLACE_PUB:
12948       /* replace entire citations */
12949       /* get list of currently selected publications */
12950       /* find publications that meet the constraint and replace them with the selected pubs */
12951       if (! ReplacePubsWithSelectedPubsByConstraint (sep, epfp))
12952       {
12953         epfp->pcp = PubConstraintFree (epfp->pcp);
12954         return;
12955       }
12956       break;
12957   }
12958   epfp->pcp = PubConstraintFree (epfp->pcp);
12959 
12960   VisitFeaturesInSep (sep, (epfp->affected_pubs), UpdateFeatureCitations);
12961   epfp->affected_pubs = AffectedPubPairListFree (epfp->affected_pubs);
12962 
12963   ObjMgrSetDirtyFlag (epfp->input_entityID, TRUE);
12964   ObjMgrSendMsg (OM_MSG_UPDATE, epfp->input_entityID, 0, 0);
12965   Update ();
12966 
12967   if (! GetStatus (epfp->leaveDlgUp))
12968   {
12969     Remove (epfp->form);
12970   }
12971 
12972 }
12973 
ChangePubEditType(GrouP g)12974 static void ChangePubEditType (GrouP g)
12975 {
12976   EditPubFormPtr epfp;
12977 
12978   epfp = (EditPubFormPtr) GetObjectExtra (g);
12979   if (epfp == NULL) return;
12980 
12981   epfp->edit_type = GetValue (epfp->edit_type_group);
12982   switch (epfp->edit_type)
12983   {
12984    case PUB_EDIT_TYPE_REPLACE_SINGLE_FIELD:
12985       Show (epfp->single_field_group);
12986       Hide (epfp->replace_sect_group);
12987       Hide (epfp->merge_auth_list_group);
12988       Hide (epfp->replace_pub_group);
12989       break;
12990     case PUB_EDIT_TYPE_REPLACE_SECTION:
12991       Hide (epfp->single_field_group);
12992       Show (epfp->replace_sect_group);
12993       Hide (epfp->merge_auth_list_group);
12994       Hide (epfp->replace_pub_group);
12995       break;
12996     case PUB_EDIT_TYPE_MERGE_AUTHOR_LISTS:
12997       Hide (epfp->single_field_group);
12998       Hide (epfp->replace_sect_group);
12999       Show (epfp->merge_auth_list_group);
13000       Hide (epfp->replace_pub_group);
13001       break;
13002     case PUB_EDIT_TYPE_REPLACE_PUB:
13003     default:
13004       Hide (epfp->single_field_group);
13005       Hide (epfp->replace_sect_group);
13006       Hide (epfp->merge_auth_list_group);
13007       Show (epfp->replace_pub_group);
13008       epfp->edit_type = PUB_EDIT_TYPE_REPLACE_PUB;
13009       SetValue (g, PUB_EDIT_TYPE_REPLACE_PUB);
13010       break;
13011   }
13012 }
13013 
LoadValueFromSelectedPub(ButtoN b)13014 static void LoadValueFromSelectedPub (ButtoN b)
13015 {
13016   EditPubFormPtr    epfp;
13017   SelStructPtr      ssp;
13018   SeqMgrFeatContext fcontext;
13019   SeqMgrDescContext dcontext;
13020   PubdescPtr        pdp = NULL;
13021   SeqFeatPtr        sfp;
13022   SeqDescPtr        sdp;
13023   CharPtr           field_val = NULL;
13024   Int4              field_to_set = PUB_FIELD_ANY;
13025   Boolean           selected_pub_found = FALSE;
13026   CharPtr           cp = NULL;
13027   Int4Ptr           retval;
13028 
13029   epfp = (EditPubFormPtr) GetObjectExtra (b);
13030   if (epfp == NULL) return;
13031 
13032   retval = DialogToPointer (epfp->field_to_set_dlg);
13033   if (retval == NULL)
13034   {
13035     return;
13036   }
13037   field_to_set = *retval;
13038   retval = MemFree (retval);
13039   if (field_to_set == PUB_FIELD_ANY) return;
13040 
13041   ssp  = ObjMgrGetSelected();
13042 
13043   while (NULL != ssp && field_val == NULL)
13044   {
13045     if (ssp->itemtype == OBJ_SEQFEAT)
13046     {
13047       sfp = SeqMgrGetDesiredFeature (ssp->entityID, NULL, ssp->itemID, 0, NULL, &fcontext);
13048       if (sfp != NULL && sfp->data.choice == SEQFEAT_PUB)
13049       {
13050         pdp = sfp->data.value.ptrvalue;
13051         field_val = GetSampleStringFromPub (pdp, field_to_set);
13052         selected_pub_found = TRUE;
13053       }
13054     }
13055     else if (ssp->itemtype == OBJ_SEQDESC)
13056     {
13057       sdp = SeqMgrGetDesiredDescriptor (ssp->entityID, NULL, ssp->itemID, 0, NULL, &dcontext);
13058       if (sdp != NULL && sdp->choice == Seq_descr_pub)
13059       {
13060         pdp = sdp->data.ptrvalue;
13061         field_val = GetSampleStringFromPub (pdp, field_to_set);
13062         selected_pub_found = TRUE;
13063       }
13064     }
13065     ssp = ssp->next;
13066   }
13067 
13068   if (!selected_pub_found)
13069   {
13070     Message (MSG_ERROR, "No publication selected - no value loaded!");
13071   }
13072   else
13073   {
13074     if (field_to_set == PUB_FIELD_MIDDLE_INITIAL
13075         && !StringHasNoText (field_val)
13076         && field_val [StringLen (field_val) - 1] == '.')
13077     {
13078       cp = field_val + StringLen (field_val) - 1;
13079       *cp = 0;
13080     }
13081     SetTitle (epfp->repl_string_txt, field_val);
13082     if (cp != NULL)
13083     {
13084       *cp = '.';
13085     }
13086   }
13087 }
13088 
CleanupEditPub(GraphiC g,VoidPtr data)13089 static void CleanupEditPub (GraphiC g, VoidPtr data)
13090 {
13091   EditPubFormPtr      epfp;
13092 
13093   epfp = (EditPubFormPtr) data;
13094   if (epfp != NULL)
13095   {
13096     /* cleanup for single field replace */
13097     epfp->repl_string = MemFree (epfp->repl_string);
13098 
13099     /* cleanup for replace section */
13100     epfp->alp = AuthListFree (epfp->alp);
13101     epfp->title_str = MemFree (epfp->title_str);
13102     epfp->affil = AffilFree (epfp->affil);
13103 
13104     /* cleanup for author list merge */
13105     epfp->names_list = FreeAuthorNameList (epfp->names_list);
13106 
13107     /* cleanup constraint */
13108     epfp->pcp = PubConstraintFree (epfp->pcp);
13109   }
13110   StdCleanupFormProc (g, data);
13111 }
13112 
EditPubsEx(BaseFormPtr bfp)13113 extern void EditPubsEx (BaseFormPtr bfp)
13114 {
13115   GrouP                 h, g, n, m, c;
13116   EditPubFormPtr        epfp;
13117   WindoW                w;
13118   ButtoN                b;
13119   PrompT                p2;
13120 
13121   if (bfp == NULL) return;
13122 
13123   epfp = (EditPubFormPtr) MemNew (sizeof (EditPubFormData));
13124   if (epfp == NULL) return;
13125   epfp->input_entityID = bfp->input_entityID;
13126   epfp->input_itemID = bfp->input_itemID;
13127   epfp->input_itemtype = bfp->input_itemtype;
13128 
13129   w = FixedWindow (-50, -33, -10, -10, "Edit Publications", StdCloseWindowProc);
13130   SetObjectExtra (w, epfp, CleanupEditPub);
13131   epfp->form = (ForM) w;
13132 
13133   h = HiddenGroup (w, -1, 0, NULL);
13134   SetGroupSpacing (h, 10, 10);
13135 
13136   epfp->edit_type_group = NormalGroup (h, 4, 0, "Type of Edit", systemFont, ChangePubEditType);
13137   SetObjectExtra (epfp->edit_type_group, epfp, NULL);
13138   RadioButton (epfp->edit_type_group, "Replace Section");
13139   RadioButton (epfp->edit_type_group, "Replace entire publication");
13140   RadioButton (epfp->edit_type_group, "Replace Single Field");
13141   RadioButton (epfp->edit_type_group, "Merge author lists");
13142   SetValue (epfp->edit_type_group, PUB_EDIT_TYPE_REPLACE_SECTION);
13143 
13144   m = HiddenGroup (h, 0, 0, NULL);
13145 
13146   epfp->single_field_group = HiddenGroup (m, -1, 0, NULL);
13147   g = HiddenGroup (epfp->single_field_group, 2, 0, NULL);
13148   StaticPrompt (g, "Set text in", 0, dialogTextHeight, programFont, 'c');
13149   epfp->field_to_set_dlg = PubFieldChoiceDialog (g, FALSE);
13150   StaticPrompt (g, "To new value", 0, dialogTextHeight, programFont, 'c');
13151   epfp->repl_string_txt = DialogText (g, "", 15, NULL);
13152   n = HiddenGroup (epfp->single_field_group, 1, 0, NULL);
13153   b = PushButton (n, "Load New Value from Selected Publication", LoadValueFromSelectedPub);
13154   SetObjectExtra (b, epfp, NULL);
13155   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) n, NULL);
13156 
13157   epfp->replace_sect_group = HiddenGroup (m, 1, 0, NULL);
13158   epfp->replace_author_list = CheckBox (epfp->replace_sect_group, "Replace Author List with Selected Author List", NULL);
13159   epfp->replace_title = CheckBox (epfp->replace_sect_group, "Replace Title with Selected Title", NULL);
13160   epfp->replace_affiliation = CheckBox (epfp->replace_sect_group, "Replace Affiliation with Selected Affiliation", NULL);
13161 
13162   epfp->merge_auth_list_group = HiddenGroup (m, -1, 0, NULL);
13163   epfp->specify_author_order = HiddenGroup (epfp->merge_auth_list_group, 0, 2, NULL);
13164   RadioButton (epfp->specify_author_order, "Automatically set author order");
13165   RadioButton (epfp->specify_author_order, "Manually set author order");
13166   SetValue (epfp->specify_author_order, 1);
13167   p2 = StaticPrompt (epfp->merge_auth_list_group,
13168                     "Authors will be selected from publications that match the constraints.",
13169                      0, dialogTextHeight, programFont, 'c');
13170   AlignObjects (ALIGN_CENTER, (HANDLE) epfp->specify_author_order,
13171                               (HANDLE) p2,
13172                               NULL);
13173 
13174   epfp->replace_pub_group = HiddenGroup (m, -1, 0, NULL);
13175   StaticPrompt (epfp->replace_pub_group, "Replace with selected publication or submitter block", 0, dialogTextHeight, programFont, 'c');
13176   ChangePubEditType (epfp->edit_type_group);
13177 
13178   AlignObjects (ALIGN_CENTER, (HANDLE) epfp->single_field_group,
13179                               (HANDLE) epfp->replace_sect_group,
13180                               (HANDLE) epfp->merge_auth_list_group,
13181                               (HANDLE) epfp->replace_pub_group,
13182                               NULL);
13183 
13184   epfp->pub_constraint_dlg = PubConstraintDialog (h);
13185 
13186   c = HiddenGroup (h, 4, 0, NULL);
13187   b = DefaultButton (c, "Accept", DoEditPubs);
13188   SetObjectExtra (b, epfp, NULL);
13189   PushButton (c, "Cancel", StdCancelButtonProc);
13190   epfp->leaveDlgUp = CheckBox (c, "Leave Dialog Up", NULL);
13191 
13192   AlignObjects (ALIGN_CENTER, (HANDLE) epfp->edit_type_group,
13193                               (HANDLE) m,
13194                               (HANDLE) epfp->pub_constraint_dlg,
13195                               (HANDLE) c,
13196                               NULL);
13197 
13198   RealizeWindow (w);
13199   Show (w);
13200   Update ();
13201 
13202 }
13203 
EditPubs(IteM i)13204 extern void EditPubs (IteM i)
13205 {
13206   BaseFormPtr           bfp;
13207 
13208 #ifdef WIN_MAC
13209   bfp = currentFormDataPtr;
13210 #else
13211   bfp = GetObjectExtra (i);
13212 #endif
13213 
13214   EditPubsEx (bfp);
13215 }
13216 
RemovePubConsortiumFromSeqFeat(SeqFeatPtr sfp,Pointer userdata)13217 static void RemovePubConsortiumFromSeqFeat (SeqFeatPtr sfp, Pointer userdata)
13218 {
13219   PubdescPtr pdp;
13220   PubPtr     pub;
13221 
13222   if (sfp == NULL || sfp->data.choice != SEQFEAT_PUB)
13223   {
13224     return;
13225   }
13226   pdp = (PubdescPtr) sfp->data.value.ptrvalue;
13227   if (pdp == NULL) return;
13228   for (pub = pdp->pub; pub != NULL; pub = pub->next)
13229   {
13230     RemoveConsortiumFromPub (pub);
13231   }
13232 }
13233 
RemovePubConsortiumFromDescr(SeqDescrPtr sdp,Pointer userdata)13234 static void RemovePubConsortiumFromDescr (SeqDescrPtr sdp, Pointer userdata)
13235 {
13236   PubdescPtr pdp;
13237   PubPtr     pub;
13238 
13239   if (sdp == NULL || sdp->choice != Seq_descr_pub)
13240   {
13241     return;
13242   }
13243   pdp = (PubdescPtr) sdp->data.ptrvalue;
13244   if (pdp == NULL) return;
13245   for (pub = pdp->pub; pub != NULL; pub = pub->next)
13246   {
13247     RemoveConsortiumFromPub (pub);
13248   }
13249 }
13250 
13251 
RemovePubConsortiumsBaseForm(BaseFormPtr bfp)13252 static void RemovePubConsortiumsBaseForm (BaseFormPtr bfp)
13253 {
13254   SeqEntryPtr           sep;
13255 
13256   if (bfp == NULL) return;
13257 
13258   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
13259   if (sep == NULL) return;
13260 
13261   VisitFeaturesInSep (sep, NULL, RemovePubConsortiumFromSeqFeat);
13262   VisitDescriptorsInSep (sep, NULL, RemovePubConsortiumFromDescr);
13263 
13264   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
13265   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
13266 }
13267 
13268 
RemovePubConsortiums(IteM i)13269 extern void RemovePubConsortiums (IteM i)
13270 {
13271   ButtonOrMenuItemTemplate(i, RemovePubConsortiumsBaseForm);
13272 }
13273 
13274 
RemovePubConsortiumsBtn(ButtoN b)13275 extern void RemovePubConsortiumsBtn (ButtoN b)
13276 {
13277   ButtonOrMenuButtonTemplate(b, RemovePubConsortiumsBaseForm);
13278 }
13279 
13280 
13281 #define MAX_ID_LEN 84
13282 
GetSeqIdPrintLen(Pointer userdata)13283 static Int4 LIBCALLBACK GetSeqIdPrintLen (Pointer userdata)
13284 {
13285   return MAX_ID_LEN + 2;
13286 }
13287 
PrintSeqId(CharPtr cp,Pointer userdata)13288 static void LIBCALLBACK PrintSeqId (CharPtr cp, Pointer userdata)
13289 {
13290   BioseqPtr bsp;
13291 
13292   bsp = (BioseqPtr) userdata;
13293   if (bsp == NULL) return;
13294 
13295   SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), cp, PRINTID_REPORT, MAX_ID_LEN);
13296   StringCat (cp, "\n");
13297 }
13298 
AddNucleotideToList(BioseqPtr seg_bsp,SeqEntryPtr PNTR nuc_list)13299 static void AddNucleotideToList (BioseqPtr seg_bsp, SeqEntryPtr PNTR nuc_list)
13300 {
13301   SeqEntryPtr  seg_sep, set_sep, prev_sep = NULL;
13302   BioseqSetPtr parent_bssp;
13303 
13304 
13305   if (seg_bsp == NULL || nuc_list == NULL)
13306   {
13307     return;
13308   }
13309 
13310   seg_sep = SeqMgrGetSeqEntryForData (seg_bsp);
13311   if (seg_bsp->idx.parenttype == OBJ_BIOSEQSET && seg_bsp->idx.parentptr != NULL)
13312   {
13313     parent_bssp = (BioseqSetPtr) seg_bsp->idx.parentptr;
13314     set_sep = parent_bssp->seq_set;
13315     prev_sep = NULL;
13316     while (set_sep != seg_sep)
13317     {
13318       prev_sep = set_sep;
13319       set_sep = set_sep->next;
13320     }
13321     if (set_sep == seg_sep)
13322     {
13323       if (prev_sep == NULL)
13324       {
13325         parent_bssp->seq_set = set_sep->next;
13326       }
13327       else
13328       {
13329         prev_sep->next = set_sep->next;
13330       }
13331       set_sep->next = NULL;
13332       ValNodeLink (nuc_list, set_sep);
13333     }
13334   }
13335 }
13336 
AddNucProtSetToList(BioseqSetPtr bssp,SeqEntryPtr PNTR set_list)13337 static void AddNucProtSetToList (BioseqSetPtr bssp, SeqEntryPtr PNTR set_list)
13338 {
13339   SeqEntryPtr  seg_sep, set_sep, prev_sep = NULL;
13340   BioseqSetPtr parent_bssp;
13341 
13342 
13343   if (bssp == NULL || set_list == NULL)
13344   {
13345     return;
13346   }
13347 
13348   seg_sep = SeqMgrGetSeqEntryForData (bssp);
13349   if (bssp->idx.parenttype == OBJ_BIOSEQSET && bssp->idx.parentptr != NULL)
13350   {
13351     parent_bssp = (BioseqSetPtr) bssp->idx.parentptr;
13352     set_sep = parent_bssp->seq_set;
13353     prev_sep = NULL;
13354     while (set_sep != seg_sep)
13355     {
13356       prev_sep = set_sep;
13357       set_sep = set_sep->next;
13358     }
13359     if (set_sep == seg_sep)
13360     {
13361       if (prev_sep == NULL)
13362       {
13363         parent_bssp->seq_set = set_sep->next;
13364       }
13365       else
13366       {
13367         prev_sep->next = set_sep->next;
13368       }
13369       set_sep->next = NULL;
13370       ValNodeLink (set_list, set_sep);
13371     }
13372   }
13373 }
13374 
AddNucOrNucProtSetToList(BioseqPtr seg_bsp,SeqEntryPtr PNTR set_list)13375 static void AddNucOrNucProtSetToList (BioseqPtr seg_bsp, SeqEntryPtr PNTR set_list)
13376 {
13377   SeqEntryPtr  top_sep;
13378   BioseqSetPtr bssp;
13379   Boolean      moved_set = FALSE;
13380 
13381   if (seg_bsp == NULL || set_list == NULL)
13382   {
13383     return;
13384   }
13385 
13386   top_sep = GetBestTopParentForData (seg_bsp->idx.entityID, seg_bsp);
13387   if (top_sep != NULL && top_sep->choice == 2 && top_sep->data.ptrvalue != NULL)
13388   {
13389     bssp = (BioseqSetPtr) top_sep->data.ptrvalue;
13390     if (bssp->_class == BioseqseqSet_class_nuc_prot)
13391     {
13392       AddNucProtSetToList (bssp, set_list);
13393       moved_set = TRUE;
13394     }
13395   }
13396   if (!moved_set)
13397   {
13398     AddNucleotideToList (seg_bsp, set_list);
13399   }
13400 }
13401 
IsBioseqMasterOrSegment(BioseqPtr bsp)13402 static Boolean IsBioseqMasterOrSegment (BioseqPtr bsp)
13403 {
13404   BioseqSetPtr bssp;
13405 
13406   if (bsp == NULL
13407       || bsp->idx.parenttype != OBJ_BIOSEQSET
13408       || bsp->idx.parentptr == NULL)
13409   {
13410     return FALSE;
13411   }
13412 
13413   bssp = (BioseqSetPtr) bsp->idx.parentptr;
13414   if (bssp->_class == BioseqseqSet_class_segset
13415       || bssp->_class == BioseqseqSet_class_parts)
13416   {
13417     return TRUE;
13418   }
13419   else
13420   {
13421     return FALSE;
13422   }
13423 }
13424 
RemoveMasterAndSegmentSequences(ValNodePtr PNTR bioseq_list)13425 static void RemoveMasterAndSegmentSequences (ValNodePtr PNTR bioseq_list)
13426 {
13427   ValNodePtr prev_vnp = NULL, next_vnp, this_vnp;
13428   BioseqPtr  bsp;
13429 
13430   if (bioseq_list == NULL)
13431   {
13432     return;
13433   }
13434 
13435   this_vnp = *bioseq_list;
13436   while (this_vnp != NULL)
13437   {
13438     next_vnp = this_vnp->next;
13439     bsp = (BioseqPtr) this_vnp->data.ptrvalue;
13440     if (IsBioseqMasterOrSegment (bsp))
13441     {
13442       if (prev_vnp == NULL)
13443       {
13444         *bioseq_list = this_vnp->next;
13445       }
13446       else
13447       {
13448         prev_vnp->next = this_vnp->next;
13449       }
13450       this_vnp->next = NULL;
13451       ValNodeFree (this_vnp);
13452     }
13453     else
13454     {
13455       prev_vnp = this_vnp;
13456     }
13457 
13458     this_vnp = next_vnp;
13459   }
13460 
13461 }
13462 
13463 /* This function allows the user to exclude sequences from the list of nucleotide sequences
13464  * to be used in the new segset.
13465  * It is similar to NewUpdateSegSet, except that it uses the selected sequences to create
13466  * a new set to be converted to the segset, instead of converting the selected set directly.
13467  */
CreateSegSet(Pointer data)13468 static Int2 LIBCALLBACK CreateSegSet (Pointer data)
13469 
13470 {
13471   OMProcControlPtr      ompcp;
13472   SeqEntryPtr           sep;
13473   ErrSev                sev;
13474   WindoW                w;
13475   GrouP                 h, g, c;
13476   ButtoN                intersperse_nulls_btn;
13477   ButtoN                fix_locus_btn;
13478   ButtoN                tax_fix_cleanup_btn;
13479   ButtoN                b;
13480   AdjustListPairData    alpd;
13481   ValNodePtr            bioseq_list = NULL;
13482   Int4                  seq_num = 0;
13483   ValNodePtr            list_pair = NULL;
13484   BioseqSetPtr          target_set = NULL;
13485   ModalAcceptCancelData acd;
13486   BioseqSetPtr          new_segset;
13487   SeqEntryPtr           new_segset_sep, dest_sep;
13488   ValNodePtr            seg_vnp, vnp;
13489   BioseqPtr             seg_bsp;
13490   SeqEntryPtr           prot_list = NULL;
13491 
13492   ompcp = (OMProcControlPtr) data;
13493   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
13494   switch (ompcp->input_itemtype) {
13495     case OBJ_BIOSEQSET :
13496       break;
13497     case 0 :
13498       return OM_MSG_RET_ERROR;
13499     default :
13500       return OM_MSG_RET_ERROR;
13501   }
13502   if (ompcp->input_data == NULL) return OM_MSG_RET_ERROR;
13503   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
13504   if (sep == NULL) return OM_MSG_RET_ERROR;
13505 
13506   /* TODO: We will want to choose as our target set the set above this one if
13507    * this set is a nuc-prot set.
13508    */
13509   target_set = (BioseqSetPtr)ompcp->input_data;
13510   if (target_set == NULL) return OM_MSG_RET_ERROR;
13511   dest_sep = SeqMgrGetSeqEntryForData (target_set);
13512   if (dest_sep == NULL) return OM_MSG_RET_ERROR;
13513 
13514   w = MovableModalWindow (-50, -33, -10, -10, "SegSet Creation Options", NULL);
13515   h = HiddenGroup (w, -1, 0, NULL);
13516   SetGroupSpacing (h, 10, 10);
13517 
13518   alpd.list_pair_dlg = DoubleListDialog (h, "Sequences for SegSet", "Sequences to Exclude",
13519                                     GetSeqIdPrintLen, PrintSeqId,
13520                                     EnableAdjustListPairAccept,
13521                                     &alpd);
13522   alpd.none_in_1_ok = FALSE;
13523   alpd.none_in_2_ok = TRUE;
13524 
13525   g = HiddenGroup (h, 0, 4, NULL);
13526   intersperse_nulls_btn = CheckBox (g, "Intersperse NULLS", NULL);
13527   SetStatus (intersperse_nulls_btn, TRUE);
13528   fix_locus_btn = CheckBox (g, "Force Locus Fixup", NULL);
13529   SetStatus (fix_locus_btn, TRUE);
13530   tax_fix_cleanup_btn = CheckBox (g, "Do Tax_Fix/Cleanup", NULL);
13531   SetStatus (tax_fix_cleanup_btn, TRUE);
13532 
13533   acd.accepted = FALSE;
13534   acd.cancelled = FALSE;
13535   c = HiddenGroup (h, 4, 0, NULL);
13536   alpd.accept_btn = DefaultButton (c, "Accept", ModalAcceptButton);
13537   SetObjectExtra (alpd.accept_btn, &acd, NULL);
13538   b = PushButton (c, "Cancel", ModalCancelButton);
13539   SetObjectExtra (b, &acd, NULL);
13540 
13541   ListBioseqsInSeqEntry (sep, TRUE, &seq_num, &bioseq_list);
13542   RemoveMasterAndSegmentSequences (&bioseq_list);
13543   ValNodeAddPointer (&list_pair, 0, bioseq_list);
13544   ValNodeAddPointer (&list_pair, 0, NULL);
13545   PointerToDialog (alpd.list_pair_dlg, list_pair);
13546   list_pair = ValNodeFree (list_pair);
13547 
13548   AlignObjects (ALIGN_CENTER, (HANDLE) alpd.list_pair_dlg,
13549                               (HANDLE) g,
13550                               (HANDLE) c,
13551                               NULL);
13552   RealizeWindow (w);
13553   Show (w);
13554   Update ();
13555 
13556   while (!acd.cancelled && ! acd.accepted)
13557   {
13558     ProcessExternalEvent ();
13559     Update ();
13560   }
13561   ProcessAnEvent ();
13562   Hide (w);
13563   if (acd.cancelled)
13564   {
13565     Remove (w);
13566   	return OM_MSG_RET_DONE;
13567   }
13568 
13569   list_pair = DialogToPointer (alpd.list_pair_dlg);
13570   if (list_pair == NULL)
13571   {
13572     return OM_MSG_RET_DONE;
13573   }
13574 
13575   new_segset = BioseqSetNew ();
13576   new_segset->_class = BioseqseqSet_class_pop_set;
13577   new_segset_sep = SeqEntryNew ();
13578   new_segset_sep->choice = 2;
13579   new_segset_sep->data.ptrvalue = new_segset;
13580 
13581   for (seg_vnp = list_pair->data.ptrvalue; seg_vnp != NULL; seg_vnp = seg_vnp->next)
13582   {
13583     seg_bsp = (BioseqPtr) seg_vnp->data.ptrvalue;
13584     if (seg_bsp == NULL)
13585     {
13586       continue;
13587     }
13588 
13589     AddNucOrNucProtSetToList (seg_bsp, &(new_segset->seq_set));
13590 
13591   }
13592 
13593   /* clean up list pair returned by dialog */
13594   for (vnp = list_pair; vnp != NULL; vnp = vnp->next) {
13595     vnp->data.ptrvalue = ValNodeFree (vnp->data.ptrvalue);
13596   }
13597   list_pair = ValNodeFree (list_pair);
13598 
13599   AddSeqEntryToSeqEntry (dest_sep, new_segset_sep, TRUE);
13600 
13601   NewSegFixup (new_segset_sep, GetStatus (intersperse_nulls_btn));
13602 
13603   AddSeqEntryToSeqEntry (new_segset_sep, prot_list, TRUE);
13604 
13605   DeleteMarkedObjects (ompcp->input_entityID, 0, NULL);
13606 
13607   if (GetStatus (fix_locus_btn))
13608   {
13609     sev = ErrSetMessageLevel (SEV_FATAL);
13610     DoFixupLocus (new_segset_sep);
13611     DoFixupSegSet (new_segset_sep);
13612     ErrSetMessageLevel (sev);
13613   }
13614 
13615   if (GetStatus (tax_fix_cleanup_btn))
13616   {
13617     ForceCleanupEntityID (ompcp->input_entityID);
13618   }
13619 
13620 
13621   Remove (w);
13622 
13623   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
13624   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
13625   Update ();
13626   return OM_MSG_RET_DONE;
13627 }
13628 
13629 
ListBioseqSetRawSequences(BioseqSetPtr bssp,ValNodePtr PNTR vnpp)13630 static void ListBioseqSetRawSequences (BioseqSetPtr bssp, ValNodePtr PNTR vnpp)
13631 {
13632   SeqEntryPtr sep;
13633   BioseqPtr   bsp;
13634   Char        id_str [128];
13635 
13636   if (bssp == NULL || bssp->_class == BioseqseqSet_class_parts || vnpp == NULL)
13637   {
13638     return;
13639   }
13640 
13641   for (sep = bssp->seq_set; sep != NULL; sep = sep->next)
13642   {
13643     if (IS_Bioseq_set (sep))
13644     {
13645       ListBioseqSetRawSequences (sep->data.ptrvalue, vnpp);
13646     }
13647     else if (IS_Bioseq (sep))
13648     {
13649       bsp = (BioseqPtr) (sep->data.ptrvalue);
13650       if (bsp != NULL)
13651       {
13652         SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), id_str, PRINTID_REPORT, sizeof (id_str) - 1);
13653         ValNodeAddPointer (vnpp, 0, StringSave (id_str));
13654       }
13655     }
13656   }
13657 }
13658 
ListRawSequencesInAlignments(GatherContextPtr gcp)13659 static Boolean ListRawSequencesInAlignments (GatherContextPtr gcp)
13660 
13661 {
13662   BioseqPtr        bsp;
13663   BioseqSetPtr     bssp;
13664   ValNodePtr PNTR  vnpp;
13665   Char             id_str [128];
13666 
13667   if (gcp == NULL || gcp->thisitem == NULL || gcp->userdata == NULL)
13668   {
13669     return TRUE;
13670   }
13671 
13672   /* don't process parts of a segmented set */
13673   if (gcp->parenttype == OBJ_BIOSEQSET
13674       && (bssp = (BioseqSetPtr) gcp->parentitem) != NULL
13675       && bssp->_class == BioseqseqSet_class_parts)
13676   {
13677     return TRUE;
13678   }
13679 
13680   vnpp = (ValNodePtr PNTR) gcp->userdata;
13681   if (vnpp == NULL) return TRUE;
13682   bsp = NULL;
13683   if (gcp->thistype == OBJ_BIOSEQ) {
13684     bsp = (BioseqPtr) gcp->thisitem;
13685     if (bsp->repr == Seq_repr_raw && IsBioseqInAnyAlignment (bsp, gcp->entityID))
13686     {
13687       SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), id_str, PRINTID_REPORT, sizeof (id_str) - 1);
13688       ValNodeAddPointer (vnpp, 0, StringSave (id_str));
13689     }
13690   } else if (gcp->thistype == OBJ_BIOSEQSET) {
13691     bssp = (BioseqSetPtr) gcp->thisitem;
13692     ListBioseqSetRawSequences (bssp, vnpp);
13693   } else return TRUE;
13694 
13695   return TRUE;
13696 }
13697 
13698 
FeatToDeltaSeq(Pointer data)13699 static Int2 LIBCALLBACK FeatToDeltaSeq (Pointer data)
13700 
13701 {
13702   BioseqPtr          bsp;
13703   SeqMgrFeatContext  context;
13704   Int4               diff;
13705   FILE               *fp;
13706   Int2               i;
13707   Int4Ptr            ivals;
13708   Int4               last;
13709   OMProcControlPtr   ompcp;
13710   Char               path [PATH_MAX];
13711   SeqFeatPtr         sfp;
13712   SeqInt             sint;
13713   SeqIdPtr           sip;
13714   Int4               start;
13715   Int4               stop;
13716   ValNode            vn;
13717 
13718   ompcp = (OMProcControlPtr) data;
13719   if (ompcp == NULL) return OM_MSG_RET_ERROR;
13720 
13721   switch (ompcp->input_itemtype) {
13722     case OBJ_SEQFEAT:
13723       sfp = (SeqFeatPtr) ompcp->input_data;
13724       break;
13725     default:
13726       return OM_MSG_RET_ERROR;
13727   }
13728 
13729   if (SeqMgrGetDesiredFeature (ompcp->input_entityID, NULL, 0, 0, sfp, &context) != sfp) return OM_MSG_RET_ERROR;
13730   bsp = BioseqFindFromSeqLoc (sfp->location);
13731   if (bsp == NULL) return OM_MSG_RET_ERROR;
13732   sip = SeqIdFindBest (bsp->id, 0);
13733   if (sip == NULL) return OM_MSG_RET_ERROR;
13734 
13735   if (! GetOutputFileName (path, sizeof (path), NULL)) return OM_MSG_RET_ERROR;
13736   fp = FileOpen (path, "w");
13737   if (fp == NULL) return OM_MSG_RET_ERROR;
13738 
13739   MemSet ((Pointer) &sint, 0, sizeof (SeqInt));
13740   MemSet ((Pointer) &vn, 0, sizeof (ValNode));
13741 
13742   fprintf (fp, ">\n");
13743   ivals = context.ivals;
13744   start = *ivals;
13745   ivals++;
13746   stop = *ivals;
13747   ivals++;
13748   sint.from = MIN (start, stop);
13749   sint.to = MAX (start, stop);
13750   sint.strand = context.strand;
13751   sint.id = sip;
13752   vn.choice = SEQLOC_INT;
13753   vn.data.ptrvalue = (Pointer) &sint;
13754   SeqLocFastaStream (&vn, fp, 0, 60, 0, 0);
13755   last = stop;
13756   for (i = 1; i < context.numivals; i++) {
13757     start = *ivals;
13758     ivals++;
13759     stop = *ivals;
13760     ivals++;
13761     diff = start - last;
13762     if (diff < 0) {
13763       diff = -diff;
13764     }
13765     if (diff > 1) {
13766       fprintf (fp, ">?%ld\n", (long) diff - 1);
13767     }
13768     sint.from = MIN (start, stop);
13769     sint.to = MAX (start, stop);
13770     sint.strand = context.strand;
13771     sint.id = sip;
13772     vn.choice = SEQLOC_INT;
13773     vn.data.ptrvalue = (Pointer) &sint;
13774     SeqLocFastaStream (&vn, fp, 0, 60, 0, 0);
13775     last = stop;
13776   }
13777 
13778   FileClose (fp);
13779   return OM_MSG_RET_ERROR;
13780 }
13781 
13782 
RemoveUnpublishedPubFeatCallback(SeqFeatPtr sfp,Pointer userdata)13783 static void RemoveUnpublishedPubFeatCallback (SeqFeatPtr sfp, Pointer userdata)
13784 {
13785   PubdescPtr pdp;
13786 
13787   if (sfp == NULL || sfp->data.choice != SEQFEAT_PUB || sfp->data.value.ptrvalue == NULL)
13788   {
13789     return;
13790   }
13791   pdp = (PubdescPtr) sfp->data.value.ptrvalue;
13792   if (GetPubStatus (pdp->pub) == PUB_STAT_UNPUBLISHED)
13793   {
13794     sfp->idx.deleteme = TRUE;
13795   }
13796 }
13797 
RemoveUnpublishedPubDescCallback(SeqDescPtr sdp,Pointer userdata)13798 static void RemoveUnpublishedPubDescCallback (SeqDescPtr sdp, Pointer userdata)
13799 {
13800   PubdescPtr    pdp;
13801   ObjValNodePtr ovp;
13802 
13803   if (sdp == NULL || sdp->choice != Seq_descr_pub || sdp->data.ptrvalue == NULL)
13804   {
13805     return;
13806   }
13807 
13808   pdp = (PubdescPtr) sdp->data.ptrvalue;
13809   if (GetPubStatus (pdp->pub) == PUB_STAT_UNPUBLISHED)
13810   {
13811     ovp = (ObjValNodePtr) sdp;
13812     ovp->idx.deleteme = TRUE;
13813   }
13814 }
13815 
13816 
RemoveUnpublishedPublicationsBaseForm(BaseFormPtr bfp)13817 NLM_EXTERN void RemoveUnpublishedPublicationsBaseForm (BaseFormPtr bfp)
13818 {
13819   SeqEntryPtr       sep;
13820   if (bfp == NULL) return;
13821 
13822   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
13823 
13824   WatchCursor ();
13825   Update ();
13826 
13827   VisitDescriptorsInSep (sep, NULL, RemoveUnpublishedPubDescCallback);
13828   VisitFeaturesInSep (sep, NULL, RemoveUnpublishedPubFeatCallback);
13829 
13830   DeleteMarkedObjects (bfp->input_entityID, 0, NULL);
13831   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
13832   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
13833   ArrowCursor ();
13834   Update ();
13835 }
13836 
13837 
RemoveUnpublishedPublications(IteM i)13838 extern void RemoveUnpublishedPublications (IteM i)
13839 {
13840   BaseFormPtr       bfp;
13841 
13842 #ifdef WIN_MAC
13843   bfp = currentFormDataPtr;
13844 #else
13845   bfp = GetObjectExtra (i);
13846 #endif
13847   RemoveUnpublishedPublicationsBaseForm(bfp);
13848 }
13849 
13850 
RemovePublishedPubFeatCallback(SeqFeatPtr sfp,Pointer userdata)13851 static void RemovePublishedPubFeatCallback (SeqFeatPtr sfp, Pointer userdata)
13852 {
13853   PubdescPtr pdp;
13854 
13855   if (sfp == NULL || sfp->data.choice != SEQFEAT_PUB || sfp->data.value.ptrvalue == NULL)
13856   {
13857     return;
13858   }
13859   pdp = (PubdescPtr) sfp->data.value.ptrvalue;
13860   if (GetPubStatus (pdp->pub) == PUB_STAT_PUBLISHED)
13861   {
13862     sfp->idx.deleteme = TRUE;
13863   }
13864 }
13865 
RemovePublishedPubDescCallback(SeqDescPtr sdp,Pointer userdata)13866 static void RemovePublishedPubDescCallback (SeqDescPtr sdp, Pointer userdata)
13867 {
13868   PubdescPtr    pdp;
13869   ObjValNodePtr ovp;
13870 
13871   if (sdp == NULL || sdp->choice != Seq_descr_pub || sdp->data.ptrvalue == NULL)
13872   {
13873     return;
13874   }
13875 
13876   pdp = (PubdescPtr) sdp->data.ptrvalue;
13877   if (GetPubStatus (pdp->pub) == PUB_STAT_PUBLISHED)
13878   {
13879     ovp = (ObjValNodePtr) sdp;
13880     ovp->idx.deleteme = TRUE;
13881   }
13882 }
13883 
RemovePublishedPublications(IteM i)13884 extern void RemovePublishedPublications (IteM i)
13885 {
13886   BaseFormPtr       bfp;
13887   SeqEntryPtr       sep;
13888 
13889 #ifdef WIN_MAC
13890   bfp = currentFormDataPtr;
13891 #else
13892   bfp = GetObjectExtra (i);
13893 #endif
13894   if (bfp == NULL) return;
13895 
13896   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
13897 
13898   WatchCursor ();
13899   Update ();
13900 
13901   VisitDescriptorsInSep (sep, NULL, RemovePublishedPubDescCallback);
13902   VisitFeaturesInSep (sep, NULL, RemovePublishedPubFeatCallback);
13903 
13904   DeleteMarkedObjects (bfp->input_entityID, 0, NULL);
13905   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
13906   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
13907   ArrowCursor ();
13908   Update ();
13909 }
13910 
13911 
PropagateMasterSourceToSegments(BioseqSetPtr bssp)13912 static void PropagateMasterSourceToSegments (BioseqSetPtr bssp)
13913 {
13914   SeqEntryPtr       sep, seg_entry;
13915   SeqDescrPtr       sdp, copy_sdp, sdp_next;
13916   SeqMgrDescContext dcontext;
13917   BioseqSetPtr      parts_set;
13918   BioseqPtr         bsp, part_bsp;
13919   ObjValNodePtr     ovp;
13920 
13921   if (bssp == NULL)
13922   {
13923     return;
13924   }
13925 
13926   if (bssp->_class == BioseqseqSet_class_segset)
13927   {
13928     sep = bssp->seq_set;
13929     /* find master segment */
13930     while (sep != NULL && (!IS_Bioseq (sep) || sep->data.ptrvalue == NULL))
13931     {
13932       sep = sep->next;
13933     }
13934     if (sep != NULL)
13935     {
13936       bsp = (BioseqPtr) sep->data.ptrvalue;
13937       sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dcontext);
13938       if (sdp != NULL)
13939       {
13940         /* don't want to copy descriptors after Bioseq */
13941         sdp_next = sdp->next;
13942         sdp->next = NULL;
13943 
13944         /* find parts set */
13945         sep = bssp->seq_set;
13946         parts_set = NULL;
13947         while (sep != NULL && parts_set == NULL)
13948         {
13949           if (IS_Bioseq_set (sep) && sep->data.ptrvalue != NULL)
13950           {
13951             parts_set = (BioseqSetPtr) sep->data.ptrvalue;
13952             if (parts_set->_class != BioseqseqSet_class_parts)
13953             {
13954               parts_set = NULL;
13955             }
13956           }
13957           sep = sep->next;
13958         }
13959         if (parts_set != NULL)
13960         {
13961           /* add a copy of the master source to each segment */
13962           for (seg_entry = parts_set->seq_set;
13963                seg_entry != NULL;
13964                seg_entry = seg_entry->next)
13965           {
13966             if (!IS_Bioseq (seg_entry) || seg_entry->data.ptrvalue == NULL)
13967             {
13968               continue;
13969             }
13970             part_bsp = (BioseqPtr) seg_entry->data.ptrvalue;
13971             copy_sdp = (SeqDescrPtr) AsnIoMemCopy (sdp,
13972                                                    (AsnReadFunc) SeqDescrAsnRead,
13973                                                    (AsnWriteFunc) SeqDescrAsnWrite);
13974             ValNodeLink (&(part_bsp->descr),copy_sdp);
13975           }
13976         }
13977         sdp->next = sdp_next;
13978         /* we want to remove the source descriptor from the master */
13979         if (sdp->extended != 0) {
13980           ovp = (ObjValNodePtr) sdp;
13981           ovp->idx.deleteme = TRUE;
13982         }
13983       }
13984     }
13985   }
13986   else
13987   {
13988     for (sep = bssp->seq_set; sep != NULL; sep = sep->next)
13989     {
13990       if (IS_Bioseq_set (sep))
13991       {
13992         PropagateMasterSourceToSegments (sep->data.ptrvalue);
13993       }
13994     }
13995   }
13996 }
13997 
13998 
CopyMasterSourceToSegments(Pointer data)13999 static Int2 LIBCALLBACK CopyMasterSourceToSegments (Pointer data)
14000 
14001 {
14002   OMProcControlPtr  ompcp;
14003   SeqEntryPtr       sep = NULL;
14004 
14005   ompcp = (OMProcControlPtr) data;
14006   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
14007   switch (ompcp->input_itemtype) {
14008     case OBJ_BIOSEQ :
14009       sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
14010       break;
14011     case OBJ_BIOSEQSET :
14012       sep = SeqMgrGetSeqEntryForData (ompcp->input_data);
14013       break;
14014     case 0 :
14015       return OM_MSG_RET_ERROR;
14016     default :
14017       return OM_MSG_RET_ERROR;
14018   }
14019   if (sep == NULL || !IS_Bioseq_set (sep) || sep->data.ptrvalue == NULL) return OM_MSG_RET_ERROR;
14020 
14021   PropagateMasterSourceToSegments(sep->data.ptrvalue);
14022 
14023   DeleteMarkedObjects (ompcp->input_entityID, 0, NULL);
14024   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
14025   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
14026   return OM_MSG_RET_DONE;
14027 }
14028 
14029 
GetNonPartialProteinsCallback(BioseqPtr bsp,Pointer userdata)14030 static void GetNonPartialProteinsCallback (BioseqPtr bsp, Pointer userdata)
14031 {
14032   SeqDescPtr        sdp;
14033   SeqMgrDescContext context;
14034   MolInfoPtr        mip;
14035 
14036   if (bsp != NULL && ISA_aa(bsp->mol) && userdata != NULL) {
14037     sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &context);
14038     /* we don't want to consider the ones that are 3' partial */
14039     if (sdp != NULL && (mip = (MolInfoPtr) sdp->data.ptrvalue) != NULL
14040         && mip->completeness != 4 /* no right */
14041         && mip->completeness != 5 /* no ends */) {
14042       ValNodeAddPointer ((ValNodePtr PNTR) userdata, OBJ_BIOSEQ, bsp);
14043     }
14044   }
14045 }
14046 
14047 
GetNonPartialProtAlign(SeqEntryPtr sep)14048 static SeqAlignPtr GetNonPartialProtAlign (SeqEntryPtr sep)
14049 {
14050   ValNodePtr protein_list = NULL;
14051   ValNodePtr vnp;
14052   SeqAlignPtr salp_head = NULL, salp_prev = NULL, salp, salp_tmp, salp_mult = NULL;
14053   BioseqPtr   master_bsp;
14054 
14055   if (sep == NULL)
14056   {
14057     return NULL;
14058   }
14059 
14060   /* get list of protein sequences */
14061   VisitBioseqsInSep (sep, &protein_list, GetNonPartialProteinsCallback);
14062   if (protein_list == NULL || protein_list->next == NULL)
14063   {
14064     protein_list = ValNodeFree (protein_list);
14065     return NULL;
14066   }
14067 
14068   /* now get protein alignment */
14069   master_bsp = protein_list->data.ptrvalue;
14070   for (vnp = protein_list->next; vnp != NULL; vnp = vnp->next)
14071   {
14072     salp = Sequin_GlobalAlign2Seq(master_bsp, vnp->data.ptrvalue, FALSE);
14073     if (salp_head != NULL && salp != NULL)
14074     {
14075       salp_prev->next = salp;
14076       salp_prev = salp;
14077     }
14078     else if (salp != NULL)
14079     {
14080       salp_head = salp_prev = salp;
14081     }
14082   }
14083   /* clean up protein list now that we are done with it */
14084   protein_list = ValNodeFree (protein_list);
14085 
14086   if (salp_head != NULL)
14087   {
14088     salp_tmp = salp_head;
14089     while (salp_tmp != NULL)
14090     {
14091        if (salp_tmp->saip != NULL)
14092        {
14093           SeqAlignIndexFree(salp_tmp->saip);
14094           salp_tmp->saip = NULL;
14095        }
14096        salp_tmp = salp_tmp->next;
14097     }
14098     AlnMgr2IndexSeqAlign(salp_head);
14099     salp_mult = AlnMgr2GetSubAlign(salp_head, 0, -1, 0, TRUE);
14100     salp_mult->dim = AlnMgr2GetNumRows(salp_head);
14101     salp_mult->type = SAT_PARTIAL;
14102     FixAlignmentEndStubs (salp_mult);
14103   }
14104 
14105   return salp_mult;
14106 }
14107 
14108 
14109 /* returns list of SeqIds that must be freed */
GetAccessionListForTruncateFromAlign(SeqAlignPtr salp,Int4 num_missing)14110 static ValNodePtr GetAccessionListForTruncateFromAlign (SeqAlignPtr salp, Int4 num_missing)
14111 {
14112   ValNodePtr        trunc_list = NULL;
14113   Int4              aln_len, i, start_seq, stop_seq, aln_pos;
14114   SeqIdPtr          sip;
14115   BioseqPtr         bsp;
14116   MolInfoPtr        mip;
14117   SeqDescPtr        sdp;
14118   SeqMgrDescContext context;
14119 
14120   if (salp == NULL || num_missing < 1) {
14121     return NULL;
14122   }
14123   AlnMgr2IndexSeqAlign(salp);
14124   aln_len = AlnMgr2GetAlnLength (salp, TRUE);
14125   for (i = 0; i < salp->dim; i++) {
14126     sip = AlnMgr2GetNthSeqIdPtr (salp, i + 1);
14127     bsp = BioseqFind (sip);
14128     if (bsp) {
14129       sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &context);
14130       /* we don't want to consider the ones that are 3' partial */
14131       if (sdp != NULL && (mip = (MolInfoPtr) sdp->data.ptrvalue) != NULL
14132           && mip->completeness != 4 /* no right */
14133           && mip->completeness != 5 /* no ends */) {
14134         AlnMgr2GetNthSeqRangeInSA(salp, i + 1, &start_seq, &stop_seq);
14135         aln_pos = AlnMgr2MapBioseqToSeqAlign(salp, stop_seq, i + 1);
14136         if (aln_len - aln_pos >= num_missing) {
14137           ValNodeAddPointer (&trunc_list, 0, sip);
14138           sip = NULL;
14139         }
14140       }
14141     }
14142     sip = SeqIdFree (sip);
14143   }
14144   return trunc_list;
14145 }
14146 
14147 
14148 typedef struct truncatebyprotalign {
14149   FORM_MESSAGE_BLOCK
14150 
14151   TexT num_missing;
14152 
14153   SeqAlignPtr salp;
14154 } TruncateByProtAlignData, PNTR TruncateByProtAlignPtr;
14155 
14156 
CleanupTruncateByProtAlignForm(GraphiC g,VoidPtr data)14157 static void CleanupTruncateByProtAlignForm (GraphiC g, VoidPtr data)
14158 {
14159   TruncateByProtAlignPtr dlg;
14160 
14161   dlg = (TruncateByProtAlignPtr) data;
14162   if (dlg != NULL) {
14163     dlg->salp = SeqAlignFree (dlg->salp);
14164   }
14165   StdCleanupFormProc (g, data);
14166 }
14167 
14168 
14169 
ShowTruncateList(ButtoN b)14170 static void ShowTruncateList (ButtoN b)
14171 {
14172   TruncateByProtAlignPtr dlg;
14173   SeqEntryPtr            sep;
14174   SeqAlignPtr            salp;
14175   ValNodePtr             trunc_list, vnp;
14176   CharPtr                val;
14177   Int4                   num_missing;
14178   LogInfoPtr             lip;
14179   Char                   id_str[200];
14180 
14181   dlg = (TruncateByProtAlignPtr) GetObjectExtra (b);
14182   if (dlg == NULL) {
14183     return;
14184   }
14185 
14186   val = SaveStringFromText (dlg->num_missing);
14187   if (StringHasNoText (val)) {
14188     val = MemFree (val);
14189     return;
14190   }
14191   num_missing = atoi (val);
14192   val = MemFree (val);
14193 
14194   sep = GetTopSeqEntryForEntityID (dlg->input_entityID);
14195   if (dlg->salp == NULL) {
14196     salp = GetNonPartialProtAlign (sep);
14197   } else {
14198     salp = dlg->salp;
14199   }
14200   trunc_list = GetAccessionListForTruncateFromAlign(salp, num_missing);
14201   if (dlg->salp == NULL) {
14202     salp = SeqAlignFree (salp);
14203   }
14204 
14205   lip = OpenLog ("Accessions");
14206   for (vnp = trunc_list; vnp != NULL; vnp = vnp->next) {
14207     SeqIdWrite (vnp->data.ptrvalue, id_str, PRINTID_FASTA_LONG, sizeof (id_str) - 1);
14208     fprintf (lip->fp, "%s\n", id_str);
14209     lip->data_in_log = TRUE;
14210   }
14211   if (!lip->data_in_log) {
14212     fprintf (lip->fp, "No accessions found\n");
14213     lip->data_in_log = TRUE;
14214   }
14215   CloseLog (lip);
14216   lip = FreeLog (lip);
14217 
14218   for (vnp = trunc_list; vnp != NULL; vnp = vnp->next) {
14219     vnp->data.ptrvalue = SeqIdFree (vnp->data.ptrvalue);
14220   }
14221   trunc_list = ValNodeFree (trunc_list);
14222 }
14223 
14224 
MarkTruncateList(ButtoN b)14225 static void MarkTruncateList (ButtoN b)
14226 {
14227   TruncateByProtAlignPtr dlg;
14228   SeqEntryPtr            sep;
14229   SeqAlignPtr            salp;
14230   ValNodePtr             trunc_list, vnp;
14231   CharPtr                val;
14232   Int4                   num_missing;
14233   BioseqPtr              prot_bsp;
14234   SeqFeatPtr             sfp, cds, mrna;
14235   SeqMgrFeatContext      context;
14236   ProtRefPtr             prp;
14237   CharPtr                orig_val, new_val;
14238   RnaRefPtr              rrp;
14239 
14240   dlg = (TruncateByProtAlignPtr) GetObjectExtra (b);
14241   if (dlg == NULL) {
14242     return;
14243   }
14244 
14245   val = SaveStringFromText (dlg->num_missing);
14246   if (StringHasNoText (val)) {
14247     val = MemFree (val);
14248     return;
14249   }
14250   num_missing = atoi (val);
14251   val = MemFree (val);
14252 
14253   sep = GetTopSeqEntryForEntityID (dlg->input_entityID);
14254   if (dlg->salp == NULL) {
14255     salp = GetNonPartialProtAlign (sep);
14256   } else {
14257     salp = dlg->salp;
14258   }
14259   trunc_list = GetAccessionListForTruncateFromAlign(salp, num_missing);
14260   if (dlg->salp == NULL) {
14261     salp = SeqAlignFree (salp);
14262   }
14263 
14264   for (vnp = trunc_list; vnp != NULL; vnp = vnp->next) {
14265     prot_bsp = BioseqFind (vnp->data.ptrvalue);
14266     sfp = SeqMgrGetNextFeature (prot_bsp, NULL, 0, FEATDEF_PROT, &context);
14267     if (sfp != NULL && (prp = (ProtRefPtr) sfp->data.value.ptrvalue) != NULL) {
14268       if (prp->name == NULL) {
14269         ValNodeAddPointer (&(prp->name), 0, StringSave ("truncated"));
14270       } else {
14271         orig_val = prp->name->data.ptrvalue;
14272         if (StringNCmp (orig_val, "truncated ", 10) != 0) {
14273           new_val = (CharPtr) MemNew (sizeof (Char) * (StringLen (orig_val) + 11));
14274           sprintf (new_val, "truncated %s", orig_val);
14275           orig_val = MemFree (orig_val);
14276           prp->name->data.ptrvalue = new_val;
14277           cds = SeqMgrGetCDSgivenProduct (prot_bsp, NULL);
14278           if (cds != NULL) {
14279             mrna = SeqMgrGetOverlappingmRNA (cds->location, &context);
14280             if (mrna != NULL) {
14281               rrp = (RnaRefPtr) mrna->data.value.ptrvalue;
14282               if (rrp->ext.choice == 1) {
14283                 rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
14284                 rrp->ext.value.ptrvalue = StringSave (new_val);
14285               }
14286             }
14287           }
14288         }
14289       }
14290     }
14291   }
14292 
14293   for (vnp = trunc_list; vnp != NULL; vnp = vnp->next) {
14294     vnp->data.ptrvalue = SeqIdFree (vnp->data.ptrvalue);
14295   }
14296   trunc_list = ValNodeFree (trunc_list);
14297 
14298   ObjMgrSetDirtyFlag (dlg->input_entityID, TRUE);
14299   ObjMgrSendMsg (OM_MSG_UPDATE, dlg->input_entityID, 0, 0);
14300   Update ();
14301 }
14302 
14303 
TruncateByProtAlign(IteM i)14304 NLM_EXTERN void TruncateByProtAlign (IteM i)
14305 {
14306   BaseFormPtr  bfp;
14307   TruncateByProtAlignPtr dlg;
14308   WindoW       w;
14309   GrouP        h, g, c;
14310   ButtoN       b;
14311   SeqEntryPtr  sep;
14312   SeqAlignPtr  salp;
14313 
14314 #ifdef WIN_MAC
14315   bfp = currentFormDataPtr;
14316 #else
14317   bfp = GetObjectExtra (i);
14318 #endif
14319   if (bfp == NULL) return;
14320 
14321   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
14322   if (sep == NULL) return;
14323   salp = ReadAlignmentForSeqEntry (sep, FALSE, TRUE, FALSE);
14324   if (salp == NULL) {
14325     return;
14326   }
14327 
14328   dlg = (TruncateByProtAlignPtr) MemNew (sizeof (TruncateByProtAlignData));
14329   dlg->input_entityID = bfp->input_entityID;
14330 
14331   dlg->salp = salp;
14332 
14333   w = FixedWindow (-50, -33, -10, -10, "Mark Truncated Products by Protein Alignment", StdCloseWindowProc);
14334   SetObjectExtra (w, dlg, StdCleanupExtraProc);
14335   dlg->form = (ForM) w;
14336 
14337   h = HiddenGroup (w, -1, 0, NULL);
14338   SetGroupSpacing (h, 10, 10);
14339 
14340   g = HiddenGroup (h, 2, 0, NULL);
14341   StaticPrompt (g, "Missing amino acids for truncation:", 0, dialogTextHeight, programFont, 'r');
14342   dlg->num_missing = DialogText (g, "10", 0, NULL);
14343   c = HiddenGroup (h, 4, 0, NULL);
14344   SetGroupSpacing (c, 10, 10);
14345 
14346   b = PushButton (c, "Make List", ShowTruncateList);
14347   SetObjectExtra (b, dlg, NULL);
14348   b = PushButton (c, "Mark List", MarkTruncateList);
14349   SetObjectExtra (b, dlg, NULL);
14350 
14351   b = PushButton (c, "Dismiss", StdCancelButtonProc);
14352 
14353   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
14354   RealizeWindow (w);
14355   Show (w);
14356   Update ();
14357 }
14358 
14359 
14360 
14361 typedef struct frameshiftdlg {
14362   FORM_MESSAGE_BLOCK
14363 
14364   WindoW aln_window;
14365   DoC    doc;
14366 
14367   SeqAlignPtr salp;
14368   SeqAnnotPtr sanp;
14369   ValNodePtr  report_list;
14370   Boolean     any_exons;
14371 
14372   FonT        title_font;
14373 } FrameShiftDlgData, PNTR FrameShiftDlgPtr;
14374 
14375 
CleanupFrameShiftDlg(GraphiC g,VoidPtr data)14376 static void CleanupFrameShiftDlg (GraphiC g, VoidPtr data)
14377 
14378 {
14379   FrameShiftDlgPtr dlg;
14380 
14381   dlg = (FrameShiftDlgPtr) data;
14382   if (dlg != NULL)
14383   {
14384     if (dlg->aln_window != NULL) {
14385       RemoveSeqEdCloseFunc (dlg->aln_window);
14386       Remove (dlg->aln_window);
14387     }
14388     dlg->sanp = SeqAnnotFree (dlg->sanp);
14389     dlg->report_list = FrameShiftReportListFree (dlg->report_list);
14390   }
14391   StdCleanupFormProc (g, data);
14392 }
14393 
14394 
ResetFrameshiftWindow(Pointer data)14395 static void ResetFrameshiftWindow (Pointer data)
14396 {
14397   FrameShiftDlgPtr  dlg;
14398 
14399   if ((dlg = (FrameShiftDlgPtr) data) != NULL) {
14400     dlg->aln_window = NULL;
14401   }
14402 }
14403 
14404 
ClickFrameShiftList(DoC d,PoinT pt)14405 static void ClickFrameShiftList (DoC d, PoinT pt)
14406 
14407 {
14408   Int2             item;
14409   Int2             row, i;
14410   FrameShiftDlgPtr dlg;
14411   ValNodePtr       vnp;
14412   FrameShiftReportPtr fr;
14413   Uint1               last_choice = eFrameShiftReport_NoReport;
14414 
14415   /* TODO - skip headers after headers are added */
14416 
14417   dlg = GetObjectExtra (d);
14418   if (dlg != NULL) {
14419     MapDocPoint (d, pt, &item, &row, NULL, NULL);
14420     if (item > 0 && row > 0) {
14421       if (item == 1 || item == 2) {
14422         vnp = dlg->report_list;
14423       } else {
14424         i = 1;
14425         vnp = dlg->report_list;
14426         while (i < item && vnp != NULL) {
14427           i++;
14428           vnp = vnp->next;
14429           if (vnp->choice != last_choice) {
14430             i++;
14431             last_choice = vnp->choice;
14432           }
14433         }
14434       }
14435       if (vnp != NULL && (fr = (FrameShiftReportPtr) vnp->data.ptrvalue) != NULL) {
14436         /* navigage alignment window to coordinate */
14437         if (dlg->aln_window == NULL) {
14438           dlg->aln_window = (WindoW) CreateAlnEditorWindowEx (33, 50, "Frameshift Alignment", dlg->salp, dlg->input_entityID, ResetFrameshiftWindow, dlg);
14439           Show (dlg->aln_window);
14440         }
14441         SeqAlnWindowScrollToAlnPos (dlg->aln_window, fr->aln_pos - 1, fr->first_related_seq);
14442       }
14443     }
14444   }
14445 }
14446 
14447 
14448 static Nlm_ParData frameshiftParFmt = {FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0};
14449 static Nlm_ColData frameshiftColFmt = {500, 0, 0, 0, NULL, 'l', 0,0,0,0, TRUE};
14450 
PopulateFrameShiftList(FrameShiftDlgPtr dlg,ValNodePtr list)14451 static void PopulateFrameShiftList (FrameShiftDlgPtr dlg, ValNodePtr list)
14452 {
14453   FrameShiftReportPtr fr;
14454   Int2                numItems;
14455   RecT                r;
14456   Uint1               last_choice = eFrameShiftReport_NoReport;
14457 
14458   if (dlg == NULL || dlg->doc == NULL)
14459   {
14460     return;
14461   }
14462 
14463   Reset (dlg->doc);
14464 
14465   ObjectRect (dlg->doc, &r);
14466   InsetRect (&r, 4, 4);
14467   frameshiftColFmt.pixWidth = r.right - r.left;
14468 
14469   while (list != NULL)
14470   {
14471     if (list->choice != last_choice) {
14472       if (list->choice == eFrameShiftReport_Exon) {
14473         AppendText (dlg->doc, "FRAMESHIFTS IN EXONS", &frameshiftParFmt, &frameshiftColFmt, dlg->title_font);
14474       } else if (list->choice == eFrameShiftReport_Intron) {
14475         if (dlg->any_exons) {
14476           AppendText (dlg->doc, "FRAMESHIFTS IN INTRONS", &frameshiftParFmt, &frameshiftColFmt, dlg->title_font);
14477         } else {
14478           AppendText (dlg->doc, "FRAMESHIFTS", &frameshiftParFmt, &frameshiftColFmt, dlg->title_font);
14479         }
14480       } else if (list->choice == eFrameShiftReport_ExonMult3) {
14481         AppendText (dlg->doc, "MULTIPLES OF THREE ARE IGNORED", &frameshiftParFmt, &frameshiftColFmt, dlg->title_font);
14482       }
14483       last_choice = list->choice;
14484     }
14485     fr = (FrameShiftReportPtr) list->data.ptrvalue;
14486     AppendText (dlg->doc, fr->msg, &frameshiftParFmt, &frameshiftColFmt, programFont);
14487     list = list->next;
14488   }
14489   GetDocParams (dlg->doc, &numItems, NULL);
14490   UpdateDocument (dlg->doc, 0, numItems);
14491 
14492 }
14493 
14494 
MakeFrameShiftReport(ButtoN b)14495 static void MakeFrameShiftReport (ButtoN b)
14496 {
14497   FrameShiftDlgPtr  dlg;
14498   LogInfoPtr        lip;
14499 
14500   dlg = (FrameShiftDlgPtr) GetObjectExtra (b);
14501   if (dlg == NULL) {
14502     return;
14503   }
14504 
14505   lip = OpenLog ("Frame Shift Report");
14506   PrintFrameShiftReportList (dlg->report_list, dlg->any_exons, FALSE, lip);
14507   CloseLog (lip);
14508   lip = FreeLog (lip);
14509 }
14510 
14511 
14512 
FrameShiftFinderEntityID(Uint2 entityID,Boolean from_clipboard)14513 NLM_EXTERN void FrameShiftFinderEntityID (Uint2 entityID, Boolean from_clipboard)
14514 {
14515   SeqEntryPtr       sep;
14516   SeqAlignPtr       salp=NULL;
14517   SeqAnnotPtr       sanp;
14518   ValNodePtr        report_list;
14519   Boolean           has_exons = FALSE;
14520   FrameShiftDlgPtr  dlg;
14521   WindoW            w;
14522   GrouP             h, c;
14523   ButtoN            b;
14524 
14525   sep = GetTopSeqEntryForEntityID (entityID);
14526   if (sep == NULL) return;
14527 
14528   salp = ReadAlignmentForSeqEntry (sep, TRUE, FALSE, from_clipboard);
14529   if (salp == NULL) {
14530     return;
14531   }
14532   sanp = SeqAnnotNew ();
14533   sanp->type = 2;
14534   sanp->data = salp;
14535   salp->idx.parentptr = sanp;
14536   salp->idx.parenttype = OBJ_SEQANNOT;
14537 
14538   /* now look for frame shifts */
14539   report_list = FindFrameShiftsInAlignment (salp, &has_exons);
14540 
14541   dlg = (FrameShiftDlgPtr) MemNew (sizeof (FrameShiftDlgData));
14542 
14543   w = FixedWindow (-50, -33, -10, -10, "FrameShift Finder", StdCloseWindowProc);
14544   dlg->form = (ForM) w;
14545   SetObjectExtra (w, dlg, CleanupFrameShiftDlg);
14546   dlg->input_entityID = entityID;
14547   dlg->salp = salp;
14548   dlg->report_list = report_list;
14549   dlg->any_exons = has_exons;
14550   dlg->aln_window = NULL;
14551 
14552   dlg->title_font = GetFont ("Arial", 12, TRUE, FALSE, FALSE, "");
14553 
14554   h = HiddenGroup (w, -1, 0, NULL);
14555   dlg->doc = DocumentPanel (h, 900, stdLineHeight * 20);
14556   SetObjectExtra (dlg->doc, dlg, NULL);
14557   SetDocAutoAdjust (dlg->doc, FALSE);
14558   SetDocProcs (dlg->doc, ClickFrameShiftList, NULL, NULL, NULL);
14559   PopulateFrameShiftList (dlg, dlg->report_list);
14560 
14561   c = HiddenGroup (h, 4, 0, NULL);
14562   b = PushButton (c, "Make Report", MakeFrameShiftReport);
14563   SetObjectExtra (b, dlg, NULL);
14564   PushButton (c, "Cancel", StdCancelButtonProc);
14565 
14566   AlignObjects (ALIGN_CENTER, (HANDLE) dlg->doc, (HANDLE) c, NULL);
14567   RealizeWindow (w);
14568   Show (w);
14569   Update ();
14570 
14571 }
14572 
14573 
FrameShiftFinderEx(IteM i,Boolean from_clipboard)14574 static void FrameShiftFinderEx (IteM i, Boolean from_clipboard)
14575 {
14576   BaseFormPtr       bfp;
14577 
14578 #ifdef WIN_MAC
14579   bfp = currentFormDataPtr;
14580 #else
14581   bfp = GetObjectExtra (i);
14582 #endif
14583   if (bfp == NULL) return;
14584 
14585   FrameShiftFinderEntityID (bfp->input_entityID, from_clipboard);
14586 }
14587 
14588 
FrameShiftFinder(IteM i)14589 NLM_EXTERN void FrameShiftFinder (IteM i)
14590 {
14591   FrameShiftFinderEx (i, FALSE);
14592 }
14593 
14594 
FrameShiftFinderClipboard(IteM i)14595 NLM_EXTERN void FrameShiftFinderClipboard (IteM i)
14596 {
14597   FrameShiftFinderEx (i, TRUE);
14598 }
14599