/***************************************************************************** # Copyright (C) 1994-2008 by David Gordon. # All rights reserved. # # This software is part of a beta-test version of the Consed/Autofinish # package. It should not be redistributed or # used for any commercial purpose, including commercially funded # sequencing, without written permission from the author and the # University of Washington. # # This software is provided ``AS IS'' and any express or implied # warranties, including, but not limited to, the implied warranties of # merchantability and fitness for a particular purpose, are disclaimed. # In no event shall the authors or the University of Washington be # liable for any direct, indirect, incidental, special, exemplary, or # consequential damages (including, but not limited to, procurement of # substitute goods or services; loss of use, data, or profits; or # business interruption) however caused and on any theory of liability, # whether in contract, strict liability, or tort (including negligence # or otherwise) arising in any way out of the use of this software, even # if advised of the possibility of such damage. # # Building Consed from source is error prone and not simple which is # why I provide executables. Due to time limitations I cannot # provide any assistance in building Consed. Even if you do not # modify the source, you may introduce errors due to using a # different version of the compiler, a different version of motif, # different versions of other libraries than I used, etc. For this # reason, if you discover Consed bugs, I can only offer help with # those bugs if you first reproduce those bugs with an executable # provided by me--not an executable you have built. # # Modifying Consed is also difficult. Although Consed is modular, # some modules are used by many other modules. Thus making a change # in one place can have unforeseen effects on many other features. # It may takes months for you to notice these other side-effects # which may not seen connected at all. It is not feasable for me to # provide help with modifying Consed sources because of the # potentially huge amount of time involved. # #*****************************************************************************/ #include "guiCheckPrimer.h" #include "handleWindowManagerDelete2.h" #include #include #include #include #include #include "popupErrorMessage.h" #include "bIsNumericMaybeWithWhitespace.h" #include using namespace std; #include "contig.h" #include "please_wait.h" #include "hp_exception_kludge.h" #include #include #include "findPrimerMatchesElsewhere.h" #include "findPrimerSelfMatches.h" #include "calculatePrimerMeltingTemperatures.h" #include "findPrimerMatchesAgainstSequencesInFile.h" #include "consedParameters.h" #include "checkPrimersForMononucleotideRepeats.h" #include "findTemplatesForPrimers.h" #include "checkPrimersForACGT.h" #include "textbox.h" #include "assembly.h" #include "consed.h" #include "whyIsPrimerNotAcceptableTypes.h" #include "createPrimerCandidate.h" #include "findStickiestSelfMatch.h" #include "primerStickiestFalseMatch.h" #include "complement_so.h" static void cbUserPushedCheckPrimer( Widget wid, XtPointer pClientData, XtPointer pCallData ) { guiCheckPrimer* pGuiCheckPrimer = (guiCheckPrimer*) pClientData; TRY_CATCH_WRAPPER( pGuiCheckPrimer->userPushedCheckPrimer(); ); } static void cbUserPushedDismiss( Widget wid, XtPointer pClientData, XtPointer pCallData ) { guiCheckPrimer* pGuiCheckPrimer = (guiCheckPrimer*) pClientData; TRY_CATCH_WRAPPER( delete pGuiCheckPrimer; ); } guiCheckPrimer :: ~guiCheckPrimer() { XtPopdown( widPopupShell_ ); XtDestroyWidget( widPopupShell_ ); } void guiCheckPrimer :: display() { widPopupShell_ = XtVaCreatePopupShell( "Check Primer", topLevelShellWidgetClass, widParentShell_, XmNtitle, (char*) "Check Primer", XmNtransient, False, XmNdeleteResponse, XmDO_NOTHING, NULL ); handleWindowManagerDelete2( widPopupShell_, cbUserPushedDismiss, this ); Widget widForm = XtVaCreateManagedWidget( "form", xmFormWidgetClass, widPopupShell_, XmNancestorSensitive, True, NULL ); const int nLabelPosition = 47; const int nFieldPosition = 53; Widget widLeftPositionLabel = XtVaCreateManagedWidget( "Left End of Primer:", xmLabelWidgetClass, widForm, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, nLabelPosition, XmNalignment, XmALIGNMENT_END, NULL ); widLeftPosition_ = XtVaCreateManagedWidget( "left", xmTextFieldWidgetClass, widForm, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, widLeftPositionLabel, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, nFieldPosition, XmNcolumns, 10, NULL ); Widget widRightPositionLabel = XtVaCreateManagedWidget( "Right End of Primer:", xmLabelWidgetClass, widForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, widLeftPosition_, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, nLabelPosition, XmNalignment, XmALIGNMENT_END, NULL ); widRightPosition_ = XtVaCreateManagedWidget( "right", xmTextFieldWidgetClass, widForm, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, widRightPositionLabel, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, nFieldPosition, XmNcolumns, 10, NULL ); Widget widStrandLabel = XtVaCreateManagedWidget( "Strand:", xmLabelWidgetClass, widForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, widRightPosition_, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, nLabelPosition, XmNalignment, XmALIGNMENT_END, NULL ); Widget widStrandRadioBox = XmCreateRadioBox( widForm, "radio", NULL, 0 ); XtVaSetValues( widStrandRadioBox, XmNtraversalOn, True, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, widRightPosition_, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, nFieldPosition, XmNorientation, XmHORIZONTAL, XmNshadowThickness, 0, XmNborderWidth, 0, XmNmarginWidth, 0, NULL ); widPointsLeft_ = XtVaCreateManagedWidget( "<-", xmToggleButtonWidgetClass, widStrandRadioBox, XmNset, False, NULL ); Widget widPointsRight = XtVaCreateManagedWidget( "->", xmToggleButtonWidgetClass, widStrandRadioBox, XmNset, True, NULL ); XtManageChild( widStrandRadioBox ); Widget widWholeCloneOrSubcloneLabel = XtVaCreateManagedWidget( "Template Type:", xmLabelWidgetClass, widForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, widStrandRadioBox, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, nLabelPosition, XmNalignment, XmALIGNMENT_END, NULL ); Widget widTypeRadioBox = XmCreateRadioBox( widForm, "radio2", NULL, 0 ); XtVaSetValues( widTypeRadioBox, XmNtraversalOn, True, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, widStrandRadioBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, nFieldPosition, XmNorientation, XmHORIZONTAL, XmNshadowThickness, 0, XmNborderWidth, 0, XmNmarginWidth, 0, NULL ); widSubcloneTemplate_ = XtVaCreateManagedWidget( "subclone", xmToggleButtonWidgetClass, widTypeRadioBox, XmNset, True, NULL ); Widget widWholeCloneTemplate = XtVaCreateManagedWidget( "whole clone", xmToggleButtonWidgetClass, widTypeRadioBox, XmNset, False, NULL ); XtManageChild( widTypeRadioBox ); Widget widCheckPrimer = XtVaCreateManagedWidget( "Check Primer", xmPushButtonWidgetClass, widForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, widTypeRadioBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 25, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 45, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, NULL ); XtAddCallback( widCheckPrimer, XmNactivateCallback, cbUserPushedCheckPrimer, this ); widDismissButton_ = XtVaCreateManagedWidget( "Dismiss", xmPushButtonWidgetClass, widForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, widTypeRadioBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 55, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 75, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, NULL ); XtAddCallback( widDismissButton_, XmNactivateCallback, cbUserPushedDismiss, this ); XtPopup( widPopupShell_, XtGrabNone ); } void guiCheckPrimer :: userPushedCheckPrimer() { // get left and right positions. Check that they numeric and // within the bounds of this contig. Get whether this is a // subclone template primer or a whole clone primer. char* szValue; szValue = XmTextFieldGetString( widLeftPosition_ ); RWCString soLeftPosition( szValue ); free( szValue ); szValue = XmTextFieldGetString( widRightPosition_ ); RWCString soRightPosition( szValue ); free( szValue ); int nUnpaddedLeft; int nUnpaddedRight; if ( !bIsNumericMaybeWithWhitespace( soLeftPosition, nUnpaddedLeft ) ) { popupErrorMessage( "left position is not numeric" ); return; } if ( !bIsNumericMaybeWithWhitespace( soRightPosition, nUnpaddedRight ) ) { popupErrorMessage( "right position is not numeric" ); return; } if ( nUnpaddedLeft > nUnpaddedRight ) { popupErrorMessage( "left position must be <= right position" ); return; } if ( nUnpaddedLeft < pContig_->nGetUnpaddedStartIndex() ) { popupErrorMessage( "%d <= left position must be true", pContig_->nGetUnpaddedStartIndex() ); return; } if ( pContig_->nGetUnpaddedEndIndex() < nUnpaddedRight ) { popupErrorMessage( "right position must be <= %d", pContig_->nGetUnpaddedEndIndex() ); return; } bool bTopStrandPrimer = ( ( XmToggleButtonGetState( widPointsLeft_ ) == True ) ? false : true ); bool bCloneNotSubcloneTemplate = ( ( XmToggleButtonGetState( widSubcloneTemplate_ ) == True ) ? false : true ); Assembly* pAssembly = ConsEd::pGetAssembly(); cout << "about to set padded to unpadded conversion table..."; cout.flush(); pAssembly->setContigMatchTablesInAllContigs(); cout << "done" << endl; cout << "about to set unpadded to padded conversion table..."; cout.flush(); cout << "done" << endl; pCP->setParametersForSequencingPrimersNotPCRPrimers( true ); // needed by nPaddedIndexFast in displayPrimers.cpp if ( bCloneNotSubcloneTemplate ) pAssembly->setAllPaddedPositionsArrays(); else pContig_->setPaddedPositionsArray(); int nUnpaddedLength = nUnpaddedRight - nUnpaddedLeft + 1; TextBox* pTB = new TextBox( "What is Wrong With This Primer", 30 ); pTB->appendWithArgs( "%s primer %s from %d to %d of %s\n", ( bCloneNotSubcloneTemplate ? "whole clone template" : "subclone template" ), ( bTopStrandPrimer ? "top strand" : "bottom strand" ), nUnpaddedLeft, nUnpaddedRight, pContig_->soGetName().data() ); if ( nUnpaddedLength < pCP->nPrimersMinimumLengthOfAPrimerToUse_ ) { pTB->appendWithArgs( "\nPrimer unacceptable because its length %d is less than the minimum length %d\n", nUnpaddedLength, pCP->nPrimersMinimumLengthOfAPrimerToUse_ ); } if ( nUnpaddedLength > pCP->nPrimersMaximumLengthOfAPrimerToUse_ ) { pTB->appendWithArgs( "\nPrimer unacceptable because its length %d is more than the maximum length %d\n", nUnpaddedLength, pCP->nPrimersMaximumLengthOfAPrimerToUse_ ); } // just so we can go on to the other checks, such as // findPrimerMatchesElsewhere, lets change the primer range pCP->nPrimersMinimumLengthOfAPrimerToUse_ = nUnpaddedLength; pCP->nPrimersMaximumLengthOfAPrimerToUse_ = nUnpaddedLength; primerType primer; createPrimerCandidate( &primer, nUnpaddedLeft, nUnpaddedLength, bTopStrandPrimer, pContig_, nUnpaddedLeft ); // nUnpaddedPosOfCursor--unimportant RWCString soPrimerBases( primer.szPrimer_, primer.nUnpaddedLength_ ); pTB->appendWithArgs( "\nsequence: %s\n", soPrimerBases.data() ); if ( primer.bAcceptable_ ) { pTB->appendWithArgs( "\nprimer bases are acceptable quality (worst is %d)\n", (int) primer.ucMinQuality_ ); } else { if ( primer.nWhyIsPrimerNotAcceptable_ == BAD_PRIMER_TOO_LOW_QUALITY ) { pTB->appendWithArgs( "\nPrimer unacceptable because bases were not all quality %d or greater\n", pCP->nPrimersMinQuality_ ); pTB->append( "This means that there is a significant probability that the \nprimer will not anneal to the desired location.\n" ); } else if ( primer.nWhyIsPrimerNotAcceptable_ == BAD_PRIMER_IN_SINGLE_SUBCLONE_REGION ) { pTB->append( "\nPrimer unacceptable because it is in a single subclone region\n" ); } else if ( primer.nWhyIsPrimerNotAcceptable_ == BAD_PRIMER_WHERE_HIGH_QUALITY_DISCREPANCIES ) { pTB->append( "\nPrimer is unacceptable because there are high quality discrepancies at its location\n" ); } else if ( primer.nWhyIsPrimerNotAcceptable_ == BAD_PRIMER_WHERE_UNALIGNED_HIGH_QUALITY_REGION ) { pTB->append( "\nPrimer is unacceptable because there is an unaligned high quality region at its location\n" ); } else { pTB->appendWithArgs( "\nPrimer is unacceptable due to reason %d\n", primer.nWhyIsPrimerNotAcceptable_ ); } } // in order to do other checks, pretend the primer has passed all // checks up to here: primer.bAcceptable_ = true; findPrimerMatchesElsewhere( &primer, 1, // nNumberOfPrimers bTopStrandPrimer, bCloneNotSubcloneTemplate ); if ( !primer.bAcceptable_ ) { pTB->append( "\nPrimer is unacceptable because it had false matches elsewhere:\n" ); } else { pTB->append( "\nPrimer does not have too severe false matches:\n" ); } RWCString soBigOutput( (size_t) 2000 ); primerStickiestFalseMatch( &primer, 1, // primer number soBigOutput ); cerr << soBigOutput << " " << soBigOutput.length() << endl; int n; for( n = 0; n < soBigOutput.length(); ++n ) putchar( soBigOutput[n] ); pTB->append( soBigOutput ); primer.bAcceptable_ = true; if ( pCP->bPrimersScreenForVector_ ) { findPrimerMatchesAgainstSequencesInFile( &primer, 1, // nNumberOfPrimers bCloneNotSubcloneTemplate ); if ( !primer.bAcceptable_ ) { pTB->append( "\nPrimer unacceptable because it has matches against vector sequence in file\n" ); } else { pTB->append( "\nPrimer does not have unacceptable matches against vector sequence in file\n" ); } } primer.bAcceptable_ = true; calculatePrimerMeltingTemperatures( &primer, 1 ); if ( !primer.bAcceptable_ ) { pTB->appendWithArgs( "\nPrimer unacceptable because melting temperature %d is not within your range of %d to %d\n", (int) primer.dMeltingTemperature_, pCP->nPrimersMinMeltingTempToUse_, pCP->nPrimersMaxMeltingTempToUse_ ); } else { pTB->appendWithArgs( "\nPrimer melting temperature %d is within range\n", (int) primer.dMeltingTemperature_ ); } primer.bAcceptable_ = true; findStickiestSelfMatch( &primer ); if ( primer.nSelfMatchScore_ > pCP->nPrimersMaxSelfMatchScore_ ) { pTB->appendWithArgs( "\nPrimer unacceptable: will form primer-dimer:\n"); } else { pTB->append( "\nPrimer will not form primer-dimer:\n" ); } pTB->appendWithArgs( "Primer self match score %d and maximum acceptable = %d\n", primer.nSelfMatchScore_, pCP->nPrimersMaxSelfMatchScore_ ); pTB->appendWithArgs( "nSelfMatchOffsetOfComplementedPrimer_ = %d nSelfMatchPosOf3PrimeSubOligo_ = %d\n", primer.nSelfMatchOffsetOfComplementedPrimer_, primer.nSelfMatchPosOf3PrimeSubOligo_ ); // show the alignment of the primer against its reverse complement: // (I could show it against itself in the reverse orientation, and then // show complementary bases, but it is easier for the eye to look // for the same bases so I show the reverse *complement* RWCString soPrimerComplement = soComplementSO( soPrimerBases ); int nSpacesBeforePrimer = 0; if ( primer.nSelfMatchOffsetOfComplementedPrimer_ < 0 ) { nSpacesBeforePrimer = -primer.nSelfMatchOffsetOfComplementedPrimer_; } for( n = 0; n < nSpacesBeforePrimer; ++n ) { pTB->append( " " ); } pTB->append( soPrimerBases ); pTB->append( "\n" ); if ( primer.nSelfMatchOffsetOfComplementedPrimer_ > 0 ) { for( n = 0; n < primer.nSelfMatchOffsetOfComplementedPrimer_; ++n ) { pTB->append( " " ); } } pTB->append( soPrimerComplement ); pTB->append( "\n" ); int nWhereToIndicateSuboligo = nSpacesBeforePrimer + primer.nSelfMatchPosOf3PrimeSubOligo_; // might need to add 1 for( n = 0; n < nWhereToIndicateSuboligo; ++n ) pTB->append( " " ); pTB->append( "^\n" ); primer.bAcceptable_ = true; int nNumberOfAcceptablePrimers; checkPrimersForMononucleotideRepeats( &primer, 1, nNumberOfAcceptablePrimers ); if ( !primer.bAcceptable_ ) { pTB->append( "\nPrimer not acceptable because of mononucleotide run\n" ); } else pTB->append( "\nPrimer does not have too long mononucleotide run\n" ); pTB->appendWithArgs( "Longest mononucleotide run = %d and threshold = %d\n", primer.nLengthOfMononucleotideRun_, pCP->nPrimersMaxLengthOfMononucleotideRepeat_ ); primer.bAcceptable_ = true; checkPrimersForACGT( &primer, 1, nNumberOfAcceptablePrimers ); if (!primer.bAcceptable_ ) { pTB->append( "\nPrimer not acceptable because there are characters besides acgt in it.\n" ); } pTB->append( "\n" ); primer.bAcceptable_ = true; if ( !bCloneNotSubcloneTemplate && pCP->bPrimersPickTemplatesForPrimers_ ) { findTemplatesForPrimers( &primer, 1, nNumberOfAcceptablePrimers, bTopStrandPrimer ); int nNumberOfTemplates = 0; for( int nTemplate = 0; nTemplate < nNUMBER_OF_TEMPLATES; ++nTemplate ) { if ( primer.pSubcloneTemplate_[ nTemplate ] ) { subcloneTTemplate* pSub = primer.pSubcloneTemplate_[ nTemplate ]; pTB->appendWithArgs( " template: %s\n", pSub->soTemplateName_.data() ); ++nNumberOfTemplates; } } if ( !primer.bAcceptable_ ) { if ( primer.nWhyIsPrimerNotAcceptable_ == BAD_PRIMER_HAS_NO_TEMPLATE ) { pTB->append( "Primer not acceptable because could not find any template for primer.\n" ); } else if ( primer.nWhyIsPrimerNotAcceptable_ == BAD_PRIMER_NOT_ENOUGH_TEMPLATES ) { pTB->appendWithArgs( "Primer not acceptable because could only find %d templates but needed a minimum of %d templates\n", nNumberOfTemplates, pCP->nPrimersMinNumberOfTemplatesForPrimers_ ); } } } pTB->makeVisible(); }