staden-lg/src/bap/oligo.c

1700 lines
39 KiB
C

/*
* File: oligo.c
* Version:
*
* Author: Simon Dear
* MRC Laboratory of Molecular Biology
* Hills Road
* Cambridge CB2 2QH
* United Kingdom
*
* Description: oligo selection module
*
* Created: 1991
* Updated: 6 November 1992
*
* 6 November 1992
* Changes for distribution
*/
#include <stdio.h>
#include <stdlib.h> /* getenv & malloc */
#include <string.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Text.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include "edUtils.h"
#include "myparams.h"
#include "defn.h"
#include "struct.h"
#include "tagUtils.h"
#include "oligo.h"
#include "misc.h"
#include "oligocom.h"
/*
* Compilation modes:
*
* NEMATODE - Make some features switchable by the environment variable SUBCLONES
* VERBOSENESS - Allow for varying degress of verbose output, including debugging information
*/
#define NEMATODE
#define VERBOSENESS
/* nematode - the drink when you're not having a drink */
int nematode;
#include "subclone.h"
/*
* Useful #defines
*/
#define FORWARDS True
#define BACKWARDS False
extern void messagef(char *format, ...);
/*
* Widgets and things
*/
static EdStruct *thisxx; /* the current EdStruct */
static int up = 0;
static Widget oldFogieWid;
static Widget oligoWid = NULL;
static Widget form;
static Widget label;
static Widget bbox, strand;
static int strand_state = FORWARDS;
static Widget cbox, change;
static Widget dbox, find, next;
static Widget template;
static Widget ebox, ok, quit;
/*
* Current state of selection
*/
static int p; /* cursor position for selection */
static int l,r; /* position of left and right ends of selection region */
static int num_oligos; /* number of oligo selected last time */
static int curr_oligo; /* number of current oligo being considered */
static Boolean oligo_sense; /* status of sense buttons when find-oligo button pressed */
static int template_index; /* gel number of current selected template */
static char template_name[DB_NAMELEN+1]; /* gel name of current selected template */
static char *consensus = NULL; /* consensus for region used to select oligo*/
/*
* Parameters for template selection
*/
#ifdef VERBOSENESS
static int verbose = 1; /* verbose output is required */
char verbosity[10]; /* space for string form of verbose */
#define verbose_debug (verbose==2 || verbose==3)
#define verbose_panic (verbose==3)
#endif /*VERBOSENESS*/
static int fwd_width = 40; /* how far ahead search window should stretch */
static int bkwd_width = 40; /* how far back search window should stretch */
static int def_insert_size = 1000; /* How far from start of template oligo can be */
static char filter[100] = "\\.[sSfFrR]1[^a-z]"; /* filter out templates from gel names */
static char clonelib[100]; /* library of subclone information: initialised in initialise()*/
static int ave_read_len = 400; /* average read length */
/*
* A few necessary forward declarations
*/
static int findOligos(EdStruct *xx, int sense);
static void nextOligo(EdStruct *xx, int oligo, int sense);
static int create_new_oligo_tag(EdStruct *xx, int oligo, int pos, int len, int sense);
static void destroy_oligo_popup();
static void destroy_temporary_tag(EdStruct *xx);
static void display_template_details();
/*********************************************************************************/
/*
* Start of code proper
*/
/*
* Callback routines
*/
static void set_strand_state(Widget w, int strand_state)
{
Arg args[2];
Cardinal nargs;
nargs = 0;
XtSetArg(args[nargs], XtNlabel, (strand_state==FORWARDS)?"------>":"<------"); nargs++;
XtSetValues(w,args,nargs);
}
static void strandCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Change strand
*/
{
strand_state = (strand_state == FORWARDS)?BACKWARDS:FORWARDS;
set_strand_state(w,strand_state);
XtCallCallbacks(find, XtNcallback, (XtPointer) NULL);
}
/*
* Move data[] outside scope of following function - non ANSI to perform
* aggregate definitions inside a function
*/
Field_entry data_1[] = {
{"Search window bases ahead", (char *)&fwd_width, t_int, sizeof(fwd_width)},
{"Search window bases back", (char *)&bkwd_width, t_int, sizeof(bkwd_width)},
{"Default insert size", (char *)&def_insert_size, t_int, sizeof(def_insert_size)},
{"Average read length", (char *)&ave_read_len, t_int, sizeof(ave_read_len)},
{"Filter to select templates", (char *)filter, t_char, sizeof(filter)},
{"Cosmid subclone library", (char *)clonelib, t_char, sizeof(clonelib)},
#ifdef VERBOSENESS
{"Verbose output?", (char *)verbosity, t_char, sizeof(verbosity)}
#endif /*VERBOSENESS*/
};
static void changeMineCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Change oligo selection parameters
*/
{
#ifdef VERBOSENESS
if (verbose_debug) message("Change my parameters\n");
/* Verbose output can be "yes", "no", "debug", or "panic"!!!! */
switch (verbose) {
case 0: strcpy(verbosity,"No"); break;
case 1: strcpy(verbosity,"Yes"); break;
case 2: strcpy(verbosity,"Debug"); break;
case 3: strcpy(verbosity,"Panic"); break;
}
#endif /*VERBOSENESS*/
change_params((Widget)w,NULL,data_1,nematode?XtNumber(data_1):4);
#ifdef VERBOSENESS
switch ( verbosity[0] ) {
case 'p': case 'P':
verbose = 3;
break;
case 'd': case 'D':
verbose = 2;
break;
case 'y': case 'Y':
verbose = 1;
break;
default:
verbose = 0;
break;
}
#endif /*VERBOSENESS*/
XtCallCallbacks(find, XtNcallback, (XtPointer) NULL);
}
static void changeParamsCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Change oligo selection parameters
*/
{
#ifdef VERBOSENESS
if (verbose_debug) message("Change selection parameters\n");
#endif /*VERBOSENESS*/
osp_change_parameters(w,&prm,0/*params*/);
XtCallCallbacks(find, XtNcallback, (XtPointer) NULL);
}
static void changeWeightsCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Change oligo selection parameters
*/
{
#ifdef VERBOSENESS
if (verbose_debug) message("Change selection weights\n");
#endif /*VERBOSENESS*/
osp_change_parameters(w,&prm,1/*weights*/);
XtCallCallbacks(find, XtNcallback, (XtPointer) NULL);
}
static void informationCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Change oligo selection parameters
*/
{
#ifdef VERBOSENESS
if (verbose_debug) message("Display information\n");
#endif /*VERBOSENESS*/
messagef("%s\n",score_info);
}
static void findCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Search for oligo
*/
{
#ifdef VERBOSENESS
if (verbose_debug) message("Find oligos\n");
#endif /*VERBOSENESS*/
oligo_sense = strand_state;
(void) findOligos(thisxx,oligo_sense);
/*
* Reveal buttons depending on result
*/
XawFormDoLayout(form,False);
if (num_oligos>0) {
XtManageChild(ok);
XtManageChild(template);
} else {
XtUnmanageChild(ok);
XtUnmanageChild(template);
}
if (num_oligos > 1)
XtManageChild(next);
else
XtUnmanageChild(next);
XawFormDoLayout(form,True);
curr_oligo = 0;
if (num_oligos>0)
nextOligo(thisxx,curr_oligo,oligo_sense);
else
destroy_temporary_tag(thisxx);
}
static void nextCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Search for oligo
*/
{
#ifdef VERBOSENESS
if (verbose_debug) message("Select next oligo\n");
#endif /*VERBOSENESS*/
curr_oligo++;
if (curr_oligo+1 == num_oligos) {
XawFormDoLayout(form,False);
XtUnmanageChild(next);
XawFormDoLayout(form,True);
}
nextOligo(thisxx,curr_oligo,oligo_sense);
}
static void okCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Select current oligo,
* Create a tag for it and everything else...
*/
{
int i = curr_oligo;
/*
* To create a new oligo a valid template must have been specified
*/
if (!template_index) {
message("A valid template has not been specified\n");
return;
}
if (oligo_sense == BACKWARDS) {
(void) create_new_oligo_tag(thisxx,i,
r-OSP_RESULTS[i].end_position,
OSP_RESULTS[i].end_position-OSP_RESULTS[i].start_position+1,
oligo_sense);
} else {
(void) create_new_oligo_tag(thisxx,i,
l+OSP_RESULTS[i].start_position,
OSP_RESULTS[i].end_position-OSP_RESULTS[i].start_position+1,
oligo_sense);
}
up = 0;
destroy_oligo_popup();
}
static void quitCallback(Widget w, XtPointer client_data, XtPointer call_data)
/*
* Leave without selecting an oligo
*/
{
up = 0;
destroy_oligo_popup();
}
/*****************************************************************************************/
static void initialise()
/*
* Initialise miscellaneous variables
*/
{
char *subclones;
/* clonelib = subclones:$SUBCLONES */
if (is_file("subclones"))
strcpy(clonelib,"subclones");
else {
subclones = (char *) getenv("SUBCLONES");
if (subclones == NULL)
clonelib[0] = '\0';
else if (is_file(subclones))
strcpy(clonelib,subclones);
else
clonelib[0] = '\0';
}
#ifdef NEMATODE
nematode=(getenv("SUBCLONES")!=NULL);
#else /*NEMATODE*/
nematode=1;
#endif /*NEMATODE*/
}
static void destroy_temporary_tag(EdStruct *xx)
/*
* Flag temporary tag as deleted
*/
{
if (DBgetTags(xx,0) != NULL) {
_delete_tag(xx, 0/*consensus*/, DBgetTags(xx,0));
}
}
static void create_temporary_tag(EdStruct *xx,int pos, int len)
/*
* Create a temporary tag in the consensus to show position of oligo under consideration
*/
{
char *defComment = "*** Temporary Annotation ***\n";
tagStruct *tempTag;
tempTag = DBgetTags(xx,0);
/*
* Create a new tag and insert it with comment into bimbo falix
*/
if (tempTag == NULL) {
tempTag = newTag();
strncpy(tempTag->tagrec.type.c,"OLIG",4);
tempTag->newcomment = (char *)malloc(strlen(defComment)+1);
strcpy(tempTag->newcomment,defComment);
tempTag->flags =
TAG_INSERTED |
TAG_LENGTH_CHANGED |
TAG_POSITION_CHANGED |
TAG_TYPE_CHANGED |
TAG_COMMENT_IN_MEMORY;
insertTag(xx,0/*consensus*/,tempTag);
}
tempTag->tagrec.position = pos;
tempTag->tagrec.length = len;
/*
* Jiggle about if tag is off screen
*/
if (xx->displayPos > pos || xx->displayPos + xx->displayWidth < pos + len )
xx->displayPos = (pos+pos+len-xx->displayWidth)/2;
redisplaySequences (xx,
xx->namesWid,
xx->sequencesWid,
xx->displayPos,
xx->displayWidth);
}
static int gel_ok(EdStruct *xx, int pos, int len, int seq)
/*
* If gel overlaps region in contig,
* return true
*/
{
return (pos >= DBgetRelPos(xx,seq) && pos+len <= DBgetRelPos(xx,seq)+DBgetLength(xx,seq));
}
static int find_gel_for_oligo(EdStruct *xx, int pos, int len, int sense, int trySeq)
/*
* Find a gel number for this oligo. Try
* (A) gel trySeq first, (if valid)
* (B) then any in the correct sense,
* (C) otherwise any at all??
* The position here is a position in the contig
*/
{
int i;
#ifdef VERBOSENESS
if (verbose_debug) messagef("Trying to find gel for oligo: pos=%d, len=%d, sense=%d\n",pos,len,sense);
#endif /*VERBOSENESS*/
/**A**/
if (trySeq > 0) {
#ifdef VERBOSENESS
if (verbose_debug) messagef("find_gel_for_oligo: Trying gel %s (%d)...\n",DBgetName(xx,trySeq),trySeq);
#endif /*VERBOSENESS*/
if ( gel_ok(xx,pos,len,trySeq) ) {
#ifdef VERBOSENESS
if (verbose_debug) messagef("Using gel %s (%d)...\n",DBgetName(xx,trySeq),trySeq);
#endif /*VERBOSENESS*/
return trySeq;
}
}
/**B**/
#ifdef VERBOSENESS
if (verbose_debug) message("find_gel_for_oligo: Trying gels in correct sense\n");
#endif /*VERBOSENESS*/
for (i=1; i<=xx->DB_gelCount ; i++) {
if (DBgetComp(xx,i) == COMPLEMENTED && sense == BACKWARDS ||
DBgetComp(xx,i) == UNCOMPLEMENTED && sense == FORWARDS) {
if (gel_ok(xx,pos,len,i)) {
#ifdef VERBOSENESS
if (verbose_debug) messagef("Using gel %s (%d)...\n",DBgetName(xx,trySeq),trySeq);
#endif /*VERBOSENESS*/
return i;
}
}
}
/**C**/
#ifdef VERBOSENESS
if (verbose_debug) message("find_gel_for_oligo: Trying any gel\n");
#endif /*VERBOSENESS*/
for (i=1; i<=xx->DB_gelCount ; i++) {
if (gel_ok(xx,pos,len,i)) {
#ifdef VERBOSENESS
if (verbose_debug) messagef("Using gel %s (%d)...\n",DBgetName(xx,trySeq),trySeq);
#endif /*VERBOSENESS*/
return i;
}
}
#ifdef VERBOSENESS
if (verbose_debug) message("find_gel_for_oligo: Failed to find any suitable gel\n");
#endif /*VERBOSENESS*/
return 0;
}
static char *generate_oligo_comment(int oligo)
{
char s[200];
char seq[100];
char *c;
int pos,len;
#ifdef VERBOSENESS
if (verbose_debug) message("creating comment for oligo:\n");
#endif /*VERBOSENESS*/
pos = OSP_RESULTS[oligo].start_position;
len = OSP_RESULTS[oligo].end_position - pos + 1;
strncpy(seq,&consensus[pos],len);
seq[len]='\0';
sprintf(s,"serial#=\ntemplate=%s\nsequence=%s\nflags=\n",template_name,seq);
#ifdef VERBOSENESS
if (verbose_debug) messagef("(%s)\n",s);
#endif /*VERBOSENESS*/
c = TAG_MALLOC(strlen(s)+1);
strcpy(c,s);
return c;
}
static int create_new_oligo_tag(EdStruct *xx, int oligo, int pos, int len, int sense)
/*
* This routine creates a new oligo tag, prior to leaving the
* oligo selection window
*/
{
tagStruct *new_oligo;
int seq;
seq = find_gel_for_oligo(xx,pos,len,sense,template_index);
if (! seq) {
messagef("NO SUITABLE GEL FOR THIS OLIGO TAG POSITION %d LENGTH %d\n",pos,len);
return 1;
}
/*
* Create a new tag and insert it with comment into bimbo falix
*/
new_oligo = newTag();
strncpy(new_oligo->tagrec.type.c,"OLIG",4);
new_oligo->tagrec.position = normalisePos(xx,seq,pos-DBgetRelPos(xx,seq)+1,len);
new_oligo->tagrec.length = len;
new_oligo->flags = TAG_INSERTED | TAG_LENGTH_CHANGED | TAG_POSITION_CHANGED | TAG_TYPE_CHANGED;
insertTag(xx,seq,new_oligo);
new_oligo->flags |= TAG_COMMENT_IN_MEMORY;
new_oligo->newcomment = generate_oligo_comment(oligo);
/*set modified tag flag */
DBsetFlags(xx,seq,DBgetFlags(xx,seq)|DB_FLAG_TAG_MODIFIED);
return 0;
}
int oligo_comp_pos(const void *pa, const void *pb)
/*
* we need to sort the oligos according to how far they are from the
* cursor position (p)
*/
{
const OSP_Results *a = (OSP_Results *)pa;
const OSP_Results *b = (OSP_Results *)pb;
#define absval(A) ( ( (A)<0 ) ? (-(A)) : (A) )
return absval((a->start_position+a->end_position)/2 - p) >
absval((b->start_position+b->end_position)/2 - p);
}
static int findOligos(EdStruct *xx, int sense)
/*
* Find suitable oligos using OSP with current parameter settings.
* Return ok status
*/
{
int seq = xx->cursorSeq;
int pos = xx->cursorPos;
int position; /* in contig */
int contigLength; /* length of contig */
int consensusLength;
int ok; /* return status from osp_analyse */
int i;
#ifdef VERBOSENESS
if (verbose_debug) message("Finding oligos...\n");
#endif /*VERBOSENESS*/
position = positionInContig(xx,seq,pos);
contigLength = DBgetLength(xx,0/*consensus*/);
/*
* Conceptually we select off consensus.
* Determine consensus around point...
* the oligo will be selected from this region
*/
if (sense == FORWARDS) {
l = (position > bkwd_width)
? position - bkwd_width : 1;
r = (position + fwd_width < contigLength)
? position + fwd_width : contigLength;
} else {
l = (position > fwd_width)
? position - fwd_width : 1;
r = (position + bkwd_width < contigLength)
? position + bkwd_width : contigLength;
}
p = bkwd_width; /* save position of cursor in consensus fragment */
consensusLength = (r-l)+1;
/* allocate space for consensus */
if (consensus != NULL) free(consensus);
consensus = (char *) malloc ( consensusLength );
DBcalcConsensus (xx,l, consensusLength, consensus, BOTH_STRANDS);
if (sense == BACKWARDS) {
/* we need to complement the consensus */
/*
* Use Rodger's routines in subs89.f
*/
sqcom_(consensus, &consensusLength, consensusLength);
sqrev_(consensus, &consensusLength, consensusLength);
}
#ifdef VERBOSENESS
if (verbose_debug) messagef("Cursor position = %d\n",pos);
if (verbose_debug) messagef("Seqence = %s (%d)\n",DBgetName(xx,seq),seq);
if (verbose_debug) messagef("Consensus for region %d-%d = (%s)\n",l,r,consensus);
if (verbose_debug) messagef("Sense = %s\n", (sense==FORWARDS)?"forward":"reverse");
#endif /*VERBOSENESS*/
/*
* A cludge to get around bug in osp_analyse
*/
for (i=0;i<MAX_NUM_OLIGOS; i++) OSP_RESULTS[i].score = 0.0;
ok=osp_analyse(OSP_RESULTS,consensus,&prm,screens,score_info);
#ifdef VERBOSENESS
if (verbose) messagef("osp_analyse returned with status %d\n", ok);
#endif /*VERBOSENESS*/
/*
* Determine number of suitable oligos
*/
if (ok)
for (num_oligos=0; OSP_RESULTS[num_oligos].score>0.0; num_oligos++);
else
num_oligos=0;
#ifdef VERBOSENESS
if (verbose) messagef("%d suitable oligos found\n",num_oligos);
#endif /*VERBOSENESS*/
/* sort? */
if (num_oligos>1) {
/* yes - sort by position relative to cursor */
qsort(OSP_RESULTS,num_oligos,sizeof(OSP_Results),oligo_comp_pos);
}
return (ok);
}
static int check_sense(EdStruct *xx, int i/*template number*/, int sense)
/*
* templates that are in the wrong sense should fail
* returns 0 - ok, 1 - wrong sense
*/
{
return (DBgetComp(xx,i) == COMPLEMENTED && sense == FORWARDS ||
DBgetComp(xx,i) == UNCOMPLEMENTED && sense == BACKWARDS);
}
static int check_5prime(EdStruct *xx, int i/*template number*/, int sense, int pos, int len)
/*
* templates that have their 5' end after the oligo position are not usable
*/
{
int relpos = DBgetRelPos(xx,i);
int length = DBgetLength(xx,i);
if (sense == FORWARDS)
return (relpos > pos);
else
return (relpos+length < pos + len);
}
static int check_template_suitability(EdStruct *xx, int i, int sense, int pos, int len)
/*
*
*/
{
int relpos = DBgetRelPos(xx,i);
int length = DBgetLength(xx,i);
int near_dist;
CloneInfo info;
char mtdname[4];
/*
* Get mtd name from gel reading name
*/
strncpy(mtdname, DBgetGelName(xx,i), 3);
mtdname[3] = '\0';
/*
* Get size information from subclones file
*/
if (read_subclone_info(clonelib,mtdname,&info))
near_dist = def_insert_size;
else
near_dist = info.range_from;
/* reject ones that are not near the required interval */
if (sense == FORWARDS)
return (pos - relpos > (near_dist-ave_read_len));
else
return (relpos+length-pos-len > (near_dist-ave_read_len));
}
static int check_template_for_oligo(EdStruct *xx,int pos, int len, int sense, int i/*template no*/)
/*
* The template number here is actually the number of an existing gel for
* that template
*
* The template:
* 1. must be in the appropriate sense.
* 2. must exists in our template library.
* 3. must be found "near" the interval required.
* 4. need not have a sequenced gel over the interval required,
* but must be past the 5' end.
*/
{
#define reject_wrong_sense 1
#define reject_mapped_after 2
#define reject_not_close 3
#define reject_not_in_library 4
/* reject ones that have a sense reverse to the one required */
if (check_sense(xx,i,sense)) {
#ifdef VERBOSENESS
if (verbose_panic) messagef(" %s rejected because it is in the wrong sense\n",DBgetName(xx,i));
#endif /*VERBOSENESS*/
return reject_wrong_sense;
}
/* reject ones with 5' end after our oligo position */
if (check_5prime(xx,i,sense,pos,len)){
#ifdef VERBOSENESS
if (verbose_panic) messagef(" %s rejected because template starts after oligo primer\n",DBgetName(xx,i));
#endif /*VERBOSENESS*/
return reject_mapped_after;
}
/*
* Check suitability of template according to position
*/
if (check_template_suitability(xx,i,sense,pos,len)){
#ifdef VERBOSENESS
if (verbose_panic) messagef(" %s rejected because template isn't near oligo primer position\n",DBgetName(xx,i));
#endif /*VERBOSENESS*/
return reject_not_close;
}
/*
* check that template exists in our template library
*/
if (0 /* ?? */) {
#ifdef VERBOSENESS
if (verbose_panic) messagef(" %s rejected because template not in template library\n",DBgetName(xx,i));
#endif /*VERBOSENESS*/
return reject_not_in_library;
}
#ifdef VERBOSENESS
if (verbose_debug) messagef(" %s selected\n",DBgetName(xx,i));
#endif /*VERBOSENESS*/
return 0;
}
static int filter_template(char *template_name)
/*
* We are interested in templates rather than simply template gel sequences
* Reject all but *.s1 *.f1 on this basis
* We are lucky in that we have a rigid nomenclature for templates
* Other people will do things differently.
*/
{
char *error_message;
error_message = (char *) re_comp(filter);
if ( error_message != NULL ) {
messagef(" Error using re_comp: %s\n",error_message);
return 0;
}
return (re_exec(template_name) == 1);
}
static int *find_templates_for_oligo (EdStruct *xx, int pos, int len, int sense)
/*
* Once an oligo has been found for the consensus at position pos, length len,
* search for a suitable template within the contig.
*
* Use existing gel readings as a basis to find a suitable template.
* As there can be several readings from one template, filter out only the
* initial reads for consideration
*/
{
static int *templateList = NULL;
int i;
int count;
if (templateList == NULL)
templateList = (int *) malloc ( xx->DB_gelCount * sizeof(int));
#ifdef VERBOSENESS
if (verbose_debug) message("Finding template for oligo:\n");
if (verbose_debug) messagef("position = %d, length = %d, forward sense=%d\n",pos,len,sense);
#endif /*VERBOSENESS*/
count = 0;
if (sense==BACKWARDS) {
for(i=1;i<=xx->DB_gelCount;i++) {
char *name;
name = DBgetGelName(xx,i);
/* only nematode extensions */
if (nematode && ! filter_template(name)) {
#ifdef VERBOSENESS
if (verbose_debug) messagef(" %s rejected because template doesn't match filter\n",DBgetName(xx,i));
#endif /*VERBOSENESS*/
continue;
}
if (! check_template_for_oligo(xx,pos,len,sense,i))
templateList[count++] = i;
}
} else {
int ind;
ind=posToIndex(xx,pos); /* optimise a bit */
if(!ind) ind=xx->DB_gelCount;
for(;ind>0;ind--) {
char *name;
i = xx->DBorder[ind];
name = DBgetGelName(xx,i);
if (nematode && ! filter_template(name)) {
#ifdef VERBOSENESS
if (verbose_debug) messagef(" %s rejected because template doesn't match filter\n",DBgetName(xx,i));
#endif /*VERBOSENESS*/
continue;
}
if (! check_template_for_oligo(xx,pos,len,sense,i))
templateList[count++] = i;
}
}
templateList[count] = 0;
return templateList;
}
#ifdef OBSELETE
static void trim_suffix(char * name)
/*
* Remove tail from first dot onwards
*/
{
char *suffix;
/* truncate at suffix */
suffix = strchr(name,'.');
if (suffix != NULL)
*suffix = '\0';
}
#endif /*OBSELETE*/
static void get_template_name(char *name, EdStruct *xx, int i)
/*
* Get the template name for gel number 'i'
*/
{
(void) strcpy(name, DBgetGelName(xx,i) );
#ifdef OBSELETE
trim_suffix(name);
#endif /*OBSELETE*/
}
#ifdef OBSELETE
static int score_reading_quality(EdStruct *xx, int seq)
/*
* Returns a score for the quality of the read, higher the better.
* Ideally it would look at the traces, but for now
* will assume length of read is a good meter for this
*/
{
return DBgetLength(xx,seq);
}
#endif /*OBSELETE*/
static int score_template(EdStruct *xx, int seq)
/*
* Score this template
*/
{
#ifdef OBSELETE
return score_reading_quality(xx,seq);
#else /*OBSELETE*/
return 1; /* this should force the first one to be chosen */
#endif /*OBSELETE*/
}
static void set_default_template(EdStruct *xx, int *templateList)
/*
* Pick a default template from the list of available templates
*/
{
template_index = 0;
template_name[0] = '\0';
if (templateList[0]) {
int i;
int score, high_score;
high_score = 0;
/* search */
for (i=0; templateList[i]; i++) {
score = score_template(xx, templateList[i]);
if (high_score < score) {
high_score = score;
template_index = templateList[i];
}
}
/* set template name */
get_template_name(template_name, xx, template_index);
}
}
#ifdef OBSELETE
static int strcmp_ignorecase(char *a, char *b)
{
for ( ; tolower(*a) == tolower(*b); a++, b++)
if (*a == '\0') return 0;
return tolower(*a) - tolower(*b);
}
#endif
static int strncmp_ignorecase(char *a, char *b, int n)
{
for ( ; n && tolower(*a) == tolower(*b); a++, b++, n--)
if (*a == '\0') return 0;
if (!n)
return 0;
else
return tolower(*a) - tolower(*b);
}
static void check_template_name(EdStruct *xx, char *template_name, int pos, int len, int sense)
/*
* Check the template name is valid
* + that it exists
* + that is in the correct sense etc etc
* If it's not valid, set template_index to be 0
*/
{
int i;
int found_index;
int template_len;
int found;
char this[DB_NAMELEN];
strcpy(this,template_name);
#ifdef OBSELETE
trim_suffix(this);
#endif /*OBSELETE*/
/*
* Check template_name exists
*/
found = 0;
template_len= strlen(template_name);
for (i=1; i<=xx->DB_gelCount ; i++) {
char *name;
name = DBgetGelName(xx,i);
if (nematode && ! filter_template(name))
continue;
if (strncmp_ignorecase(template_name, DBgetGelName(xx,i), template_len) == 0) {
found++;
found_index = i;
#ifdef VERBOSENESS
if (verbose_debug) messagef("%s matches %s\n",template_name,DBgetName(xx,i));
#endif /*VERBOSENESS*/
}
}
template_index = 0;
if (! found)
messagef("template %s not found\n", template_name);
else {
if (found > 1) {
#ifdef VERBOSENESS
if (verbose_debug) messagef("template %s found, but is not unique\n",
template_name);
#endif /*VERBOSENESS*/
} else {
if (check_sense(xx, found_index, sense)) {
messagef("template %s in the wrong sense\n", template_name);
return;
}
if (check_5prime(xx,found_index,sense,pos,len)) {
messagef("template %s starts after oligo position\n", template_name);
return;
}
template_index = found_index;
}
}
}
/*
* Move data[] outside scope of following function - non ANSI to perform
* aggregate definitions inside a function
*/
Field_entry data_2[] = {
{"Template", (char *)template_name, t_char, sizeof(template_name)},
};
static void menuSelectCallback(Widget w, XtPointer p_i, XtPointer junk)
/*
* A template has been selected off the menu
* Deal with it
*/
{
int i = (int) p_i;
/*
* i is either -1 (other) or the gel number corresponding to a template
*/
if (i<0) {
#ifdef VERBOSENESS
if (verbose_debug) message("Menu: Other selected\n");
#endif /*VERBOSENESS*/
template_name[0]='\0';
change_params((Widget)oligoWid,"Please specify...",data_2,
XtNumber(data_2));
template_index = 0;
if (oligo_sense == BACKWARDS) {
check_template_name(thisxx, template_name,
r-OSP_RESULTS[curr_oligo].end_position,
OSP_RESULTS[curr_oligo].end_position-OSP_RESULTS[curr_oligo].start_position+1,
oligo_sense);
} else {
check_template_name(thisxx, template_name,
l+OSP_RESULTS[curr_oligo].start_position,
OSP_RESULTS[curr_oligo].end_position-OSP_RESULTS[curr_oligo].start_position+1,
oligo_sense);
}
} else {
template_index = i;
get_template_name(template_name,thisxx,i);
#ifdef VERBOSENESS
if (verbose_debug) messagef("Menu: %s selected\n", template_name);
#endif /*VERBOSENESS*/
}
display_template_details();
}
static void create_template_menu(EdStruct *xx, int *list)
/*
* Create new list of available templates
*/
{
static Widget menuWid = NULL;
int i;
Widget entryWid;
Arg args[2];
Cardinal nargs;
if (menuWid != NULL)
XtDestroyWidget(menuWid);
/*
* Create the menu parent widget
*/
menuWid = XtCreatePopupShell("templateMenu", simpleMenuWidgetClass, template,
NULL, 0);
/*
Put the individual items in.
When selected, each entry will generate a callback with
its associated number.
*/
for (i = 0; list[i]; i++)
{
char name[DB_NAMELEN];
#ifdef VERBOSENESS
if (verbose_debug) messagef("Creating menu for %s\n",DBgetName(xx,list[i]));
#endif /*VERBOSENESS*/
/*
* Prepare clone name
*/
get_template_name(name, xx, list[i]);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, name); nargs++;
entryWid = XtCreateManagedWidget("entry", smeBSBObjectClass,
menuWid, args, nargs);
XtAddCallback(entryWid, XtNcallback, menuSelectCallback,
(XtPointer) list[i]);
}
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Other"); nargs++;
entryWid = XtCreateManagedWidget("entry", smeBSBObjectClass,
menuWid, args, nargs);
XtAddCallback(entryWid, XtNcallback, menuSelectCallback,
(XtPointer) -1);
}
static void display_template_details()
/*
* Display importand template details
*/
{
if (template_index > 0) {
messagef("Template: %s\n", template_name);
} else {
message("Template: none chosen\n");
}
}
static void display_oligo_details(EdStruct *xx, int sense, int oligo)
/*
* Display important oligo details
* a. sequence
* b. position, length
* c. osp score, gc, tm
*/
{
char seq[100];
int pos,len;
int i;
char *a;
int consensus_start, consensus_end;
pos = OSP_RESULTS[oligo].start_position;
len = OSP_RESULTS[oligo].end_position - pos + 1;
/*
* Get consensus sequence with context
*/
a = seq;
for (i=3;i;i--) *a++ = '.';
for (i=(pos>2)?2:pos;i;i--)
*a++ = tolower(consensus[pos-i]);
strncpy(a,&consensus[pos],len); a+=len;
for (i=0;i<2&&consensus[pos+len+i];i++)
*a++ = tolower(consensus[pos+len+i]);
for (i=3;i;i--) *a++ = '.';
*a++ = '\0';
/*
* Positions in contig
*/
if (sense == BACKWARDS) {
consensus_start = r-OSP_RESULTS[oligo].end_position;
consensus_end = consensus_start + len - 1;
} else {
consensus_start = l+OSP_RESULTS[oligo].start_position;
consensus_end = consensus_start + len - 1;
}
messagef("Oligo: %s\n",seq);
messagef("\
Primer # %2d PRIMER-SELF PRIMER-OTHER\n\
5' end 3' end length Score G+C(%%) Tm 3' Internal 3' Internal\n\
%6d %6d %4d %4.1f %4.1f %4.1f %4.1f %4.1f %4.1f %4.1f\n",
oligo+1,
consensus_start,
consensus_end,
len,
OSP_RESULTS[oligo].score,
OSP_RESULTS[oligo].gc * 100.0,
OSP_RESULTS[oligo].tm,
OSP_RESULTS[oligo].psI_score,
OSP_RESULTS[oligo].ps3_score,
OSP_RESULTS[oligo].poI_score,
OSP_RESULTS[oligo].po3_score);
}
static void nextOligo(EdStruct *xx, int oligo, int sense)
/*
* We cycle through the oligo list
* curr-oligo gives the current oligo entry under consideration
*/
{
/*
* Hilight position of next oligo in contig editor temporarily
*/
int *templateList;
int i = oligo;
/*
* Print out information on oligos
*/
#ifdef VERBOSENESS
if (verbose_debug) messagef("************** %d ************\n",i);
if (verbose_debug) messagef("stp %d, endp %d, score %f, gc %f, tm %f, psI %f ps3 %f poI %f po3 %f\n",
OSP_RESULTS[i].start_position,
OSP_RESULTS[i].end_position,
OSP_RESULTS[i].score,
OSP_RESULTS[i].gc,
OSP_RESULTS[i].tm,
OSP_RESULTS[i].psI_score,
OSP_RESULTS[i].ps3_score,
OSP_RESULTS[i].poI_score,
OSP_RESULTS[i].po3_score);
#endif /*VERBOSENESS*/
display_oligo_details(xx,sense,i);
if (sense == BACKWARDS) {
/*
* Convert position returned from oligo selection to
* position in contig
*/
templateList =
find_templates_for_oligo(xx,
r-OSP_RESULTS[i].end_position,
OSP_RESULTS[i].end_position-OSP_RESULTS[i].start_position+1,
sense);
create_temporary_tag(xx,
r-OSP_RESULTS[i].end_position,
OSP_RESULTS[i].end_position-OSP_RESULTS[i].start_position+1);
} else {
/*
* Convert position returned from oligo selection to
* position in contig
*/
templateList =
find_templates_for_oligo(xx,
l+OSP_RESULTS[i].start_position,
OSP_RESULTS[i].end_position-OSP_RESULTS[i].start_position+1,
sense);
create_temporary_tag(xx,
l+OSP_RESULTS[i].start_position,
OSP_RESULTS[i].end_position-OSP_RESULTS[i].start_position+1);
}
set_default_template(xx,templateList);
create_template_menu(xx, templateList);
display_template_details();
}
/*****************************************************************************************/
/*
* External routines
*/
void createOligoWidget(Widget parentWid)
/*
* Prtend to create it now
*/
{
oldFogieWid = parentWid;
}
static void create_oligo_wid(Widget parentWid)
/*
* Create the window for oligo selection
* This routine should be called just once, in the initialisation phase of xdap
*/
{
Cardinal nargs;
Arg args[10];
Position x, y; /* top-left hand corner of new widget */
Dimension height; /* height of parent widget */
/*
* Determine the position on the screen for this widget
*/
#define fromVertWid (thisxx->edWid)
nargs = 0;
XtSetArg(args[nargs], XtNheight, &height); nargs++;
XtGetValues(fromVertWid, args, nargs);
XtTranslateCoords(fromVertWid, (Position) 0, (Position) height, &x, &y);
/*
* Create popup shell
*/
nargs = 0;
XtSetArg(args[nargs], XtNx, x); nargs++;
XtSetArg(args[nargs], XtNy, y); nargs++;
oligoWid = XtCreatePopupShell("oligo", transientShellWidgetClass, parentWid, args, nargs);
/*
* Create main form
*/
nargs = 0;
form = XtCreateManagedWidget("form", formWidgetClass, oligoWid, args, nargs);
/*
* Create title for form
*/
nargs = 0;
XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
XtSetArg(args[nargs], XtNlabel, "Select Oligos and Templates"); nargs++;
label = XtCreateManagedWidget("label", labelWidgetClass, form, args, nargs);
#define XtOrientHorizontal "horizontal"
/*
* Create buttons for oligo sense
*/
nargs = 0;
XtSetArg(args[nargs], XtNfromVert, label); nargs++;
XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
XtSetArg(args[nargs], XtNorientation, XtOrientHorizontal); nargs++;
bbox = XtCreateManagedWidget("bbox", boxWidgetClass, form, args, nargs);
nargs = 0;
XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
XtSetArg(args[nargs], XtNlabel, "Direction:"); nargs++;
(void) XtCreateManagedWidget("label", labelWidgetClass, bbox, args, nargs);
nargs = 0;
strand = XtCreateManagedWidget("strand", commandWidgetClass,bbox,args,nargs);
XtAddCallback(strand, XtNcallback, strandCallback, (XtPointer) NULL);
set_strand_state(strand,strand_state);
/*
* Create Change Parameter Buttons
*/
nargs = 0;
XtSetArg(args[nargs], XtNfromVert, bbox); nargs++;
XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
XtSetArg(args[nargs], XtNorientation, XtOrientHorizontal); nargs++;
cbox = XtCreateManagedWidget("cbox", boxWidgetClass, form, args, nargs);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Parameters"); nargs++;
change = XtCreateManagedWidget("change", commandWidgetClass, cbox, args, nargs);
XtAddCallback(change, XtNcallback, changeMineCallback, (XtPointer) NULL);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Oligo Selection Parameters"); nargs++;
change = XtCreateManagedWidget("change", commandWidgetClass, cbox, args, nargs);
XtAddCallback(change, XtNcallback, changeParamsCallback, (XtPointer) NULL);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Oligo Selection Weights"); nargs++;
change = XtCreateManagedWidget("change", commandWidgetClass, cbox, args, nargs);
XtAddCallback(change, XtNcallback, changeWeightsCallback, (XtPointer) NULL);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Display Selection Information"); nargs++;
change = XtCreateManagedWidget("information", commandWidgetClass, cbox, args, nargs);
XtAddCallback(change, XtNcallback, informationCallback, (XtPointer) NULL);
/*
* Create action button
*/
nargs = 0;
XtSetArg(args[nargs], XtNfromVert, cbox); nargs++;
XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
XtSetArg(args[nargs], XtNorientation, XtOrientHorizontal); nargs++;
XtSetArg(args[nargs], XtNresizable, True); nargs++;
dbox = XtCreateManagedWidget("dbox", boxWidgetClass, form, args, nargs);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Find Oligos"); nargs++;
find = XtCreateManagedWidget("find", commandWidgetClass, dbox, args, nargs);
XtAddCallback(find, XtNcallback, findCallback, (XtPointer) NULL);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Select Next"); nargs++;
next = XtCreateManagedWidget("next", commandWidgetClass, dbox, args, nargs);
XtAddCallback(next, XtNcallback, nextCallback, (XtPointer) NULL);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Choose Template for this Oligo"); nargs++;
XtSetArg(args[nargs], XtNmenuName, "templateMenu"); nargs++;
template = XtCreateManagedWidget("template", menuButtonWidgetClass, dbox, args, nargs);
/*
* Exit action
*/
nargs = 0;
XtSetArg(args[nargs], XtNfromVert, dbox); nargs++;
XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
XtSetArg(args[nargs], XtNorientation, XtOrientHorizontal); nargs++;
XtSetArg(args[nargs], XtNresizable, True); nargs++;
ebox = XtCreateManagedWidget("ebox", boxWidgetClass, form, args, nargs);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Create Tag for this Oligo"); nargs++;
ok = XtCreateManagedWidget("ok", commandWidgetClass, ebox, args, nargs);
XtAddCallback(ok, XtNcallback, okCallback, (XtPointer) NULL);
nargs = 0;
XtSetArg(args[nargs], XtNlabel, "Quit"); nargs++;
quit = XtCreateManagedWidget("quit", commandWidgetClass, ebox, args, nargs);
XtAddCallback(quit, XtNcallback, quitCallback, (XtPointer) NULL);
}
int invokeOligo(EdStruct *xx)
/*
* Pop up the oligo selection window
*/
{
if (up) return 0;
thisxx = xx;
if (oligoWid == NULL) {
initialise();
osp_initialise();
create_oligo_wid(oldFogieWid);
}
XtUnmanageChild(ok);
XtUnmanageChild(next);
XtUnmanageChild(template);
XtPopup(oligoWid, XtGrabNone);
up = 1;
/* find oligos */
XtCallCallbacks(find, XtNcallback, (XtPointer) NULL);
return 0;
}
int destroyOligo()
/*
* Shut this baby down
*/
{
if (up)
XtCallCallbacks(quit, XtNcallback, (XtPointer) NULL);
return 0;
}
static void destroy_oligo_popup()
/*
* Popdown the oligo popup window,
* free a few variables
* then relax
*/
{
EdStruct *xx = thisxx;
XtPopdown(oligoWid);
destroy_temporary_tag(xx);
free (consensus);
consensus = NULL;
redisplaySequences (xx,
xx->namesWid,
xx->sequencesWid,
xx->displayPos,
xx->displayWidth);
}