/***************************************************************************** # 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 "guiReorderContigs.h" #include "handleWindowManagerDelete2.h" #include #include #include #include #include #include #include "consed.h" #include "hp_exception_kludge.h" #include "guiapp.h" #include #include #include "popupErrorMessage2.h" #include "editAddConsensusTag.h" #include "editDeleteConsensusTag.h" #include "contigEndPair.h" #include "bGuiGetAnswerYesNo.h" #include "assemblyView.h" static void cbAddContigEndPair( Widget wid, XtPointer pClientData, XtPointer pCallData ) { TRY_CATCH_WRAPPER( guiReorderContigs* pGuiReorderContigs = (guiReorderContigs*) pClientData; pGuiReorderContigs->userPushedAdd(); ); } static void cbDeleteContigEndPair( Widget wid, XtPointer pClientData, XtPointer pCallData ) { TRY_CATCH_WRAPPER( guiReorderContigs* pGuiReorderContigs = (guiReorderContigs*) pClientData; pGuiReorderContigs->userPushedDelete(); ) } static void cbUserPushedDismiss( Widget wid, XtPointer pClientData, XtPointer pCallData ) { TRY_CATCH_WRAPPER( guiReorderContigs* pGuiReorderContigs = (guiReorderContigs*) pClientData; delete pGuiReorderContigs; ); } void guiReorderContigs :: createWindow() { Assembly* pAssembly = ConsEd::pGetAssembly(); widPopupShell_ = XtVaCreatePopupShell( "Reorder Contigs", topLevelShellWidgetClass, GAPP->widGetTopLevel(), XmNtransient, False, XmNdeleteResponse, XmDO_NOTHING, NULL ); handleWindowManagerDelete2( widPopupShell_, cbUserPushedDismiss, this ); Widget widForm = XtVaCreateManagedWidget( "form", xmFormWidgetClass, widPopupShell_, NULL ); Widget widAddLineForm = XtVaCreateManagedWidget( "addLineForm", xmFormWidgetClass, widForm, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, NULL ); Widget widAbove = widAddLineForm; Widget widLabel1 = XtVaCreateManagedWidget( "Contig:", xmLabelWidgetClass, widAddLineForm, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL ); widContig1_ = XtVaCreateManagedWidget( "contig1", xmTextFieldWidgetClass, widAddLineForm, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widLabel1, XmNcolumns, 7, NULL ); Widget widEnd1RadioBox = XmCreateRadioBox( widAddLineForm, "radio1", NULL, 0 ); XtVaSetValues( widEnd1RadioBox, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widContig1_, XmNorientation, XmHORIZONTAL, NULL ); XtManageChild( widEnd1RadioBox ); widLeftEndContig1_ = XtVaCreateManagedWidget( "Left End", xmToggleButtonWidgetClass, widEnd1RadioBox, XmNset, True, // default NULL ); Widget widRightEndContig1 = XtVaCreateManagedWidget( "Right End", xmToggleButtonWidgetClass, widEnd1RadioBox, XmNset, False, // default NULL ); Widget widLabel2 = XtVaCreateManagedWidget( "connected to Contig:", xmLabelWidgetClass, widAddLineForm, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widEnd1RadioBox, NULL ); widContig2_ = XtVaCreateManagedWidget( "contig2", xmTextFieldWidgetClass, widAddLineForm, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widLabel2, XmNcolumns, 7, NULL ); Widget widEnd2RadioBox = XmCreateRadioBox( widAddLineForm, "radio2", NULL, 0 ); XtVaSetValues( widEnd2RadioBox, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widContig2_, XmNorientation, XmHORIZONTAL, XmNshadowThickness, 0, XmNborderWidth, 0, XmNmarginWidth, 0, NULL ); widLeftEndContig2_ = XtVaCreateManagedWidget( "Left End", xmToggleButtonWidgetClass, widEnd2RadioBox, XmNset, True, // default NULL ); Widget widRightEndContig2 = XtVaCreateManagedWidget( "Right End", xmToggleButtonWidgetClass, widEnd2RadioBox, XmNset, False, // default NULL ); XtManageChild( widEnd2RadioBox ); Widget widAddContigEndPair = XtVaCreateManagedWidget( "Add and Restart Assembly View", xmPushButtonWidgetClass, widForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, widAbove, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 40, NULL ); widAbove = widAddContigEndPair; XtAddCallback( widAddContigEndPair, XmNactivateCallback, cbAddContigEndPair, this ); // start from bottom up widDismiss_ = XtVaCreateManagedWidget( "Dismiss", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 40, NULL ); XtAddCallback( widDismiss_, XmNactivateCallback, cbUserPushedDismiss, this ); Widget widBelow = widDismiss_; Widget widDeleteContigEndPair = XtVaCreateManagedWidget( "Delete Selected and Restart Assembly View", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widBelow, XmNbottomOffset, 20, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 40, NULL ); XtAddCallback( widDeleteContigEndPair, XmNactivateCallback, cbDeleteContigEndPair, this ); widBelow = widDeleteContigEndPair; int nArgs = 0; Arg aArg[500]; XtSetArg( aArg[nArgs], XmNselectionPolicy, XmSINGLE_SELECT ); ++nArgs; XtSetArg( aArg[nArgs], XmNtopAttachment, XmATTACH_WIDGET ); ++nArgs; XtSetArg( aArg[nArgs], XmNtopWidget, widAbove ); ++nArgs; XtSetArg( aArg[nArgs], XmNbottomAttachment, XmATTACH_WIDGET ); ++nArgs; XtSetArg( aArg[nArgs], XmNbottomWidget, widBelow ); ++nArgs; XtSetArg( aArg[nArgs], XmNvisibleItemCount, 3 ); ++nArgs; XtSetArg( aArg[nArgs], XmNleftAttachment, XmATTACH_FORM ); ++nArgs; XtSetArg( aArg[nArgs], XmNrightAttachment, XmATTACH_FORM ); ++nArgs; widContigEndPairList_ = XmCreateScrolledList( widForm, "list", aArg, nArgs ); XtManageChild( widContigEndPairList_ ); XtPopup( widPopupShell_, XtGrabNone ); setExistingUserDefinedContigEndPairs(); } void guiReorderContigs :: restartAssemblyView() { // save this on the stack, in case the memory is freed up by the dtor assemblyView* pASV = pAssemblyView_; // not needed because assemblyView dtor will delete us // delete this; delete pASV; ConsEd::pGetConsEd()->pAssemblyView_ = new assemblyView( ); ConsEd::pGetConsEd()->pAssemblyView_->createWindow( ConsEd::pGetAssembly() ); } guiReorderContigs :: ~guiReorderContigs() { XtPopdown( widPopupShell_ ); XtDestroyWidget( widPopupShell_ ); if ( pAssemblyView_ ) { pAssemblyView_->pGuiReorderContigs_ = NULL; } } void guiReorderContigs :: userPushedAdd() { RWCString soContig0 = XmTextFieldGetString( widContig1_ ); RWCString soContig1 = XmTextFieldGetString( widContig2_ ); int nContigEnd[2]; nContigEnd[0] = ( XmToggleButtonGetState( widLeftEndContig1_ ) == True ) ? nLeftGap : nRightGap; nContigEnd[1] = ( XmToggleButtonGetState( widLeftEndContig2_ ) == True ) ? nLeftGap : nRightGap; // check that soContig0 and soContig1 are both legitimate Contig* pContig[2]; Assembly* pAssembly = ConsEd::pGetAssembly(); int nContig; for( nContig = 0; nContig <= 1; ++nContig ) { RWCString& soContig = ( nContig == 0 ? soContig0 : soContig1 ); pContig[ nContig ] = pAssembly->pGetContigByVariousNames( soContig ); if ( ! pContig[ nContig ] ) { popupErrorMessage2( widPopupShell_, "contig %s does not exist--please change this name", soContig.data() ); return; } } // let's see if it contradicts some existing contigEndPair. In // case the user has added a number of user-defined contigEndPairs // at once before pushing "RestartAssemblyView", we should also check that it // doesn't conflict with some previously-added contigEndPair bool bError = false; RWCString soErrorMessage; RWTPtrOrderedVector aUserDefinedContigEndPairs; pAssembly->getUserDefinedContigEndPairs( aUserDefinedContigEndPairs ); int nContigEndPair; for( nContigEndPair = 0; nContigEndPair < aUserDefinedContigEndPairs.length(); ++nContigEndPair ) { contigEndPair* pCEP = aUserDefinedContigEndPairs[ nContigEndPair ]; for( int nContigEnd1 = 0; nContigEnd1 <= 1; ++nContigEnd1 ) { for( int nContigEnd2 = 0; nContigEnd2 <= 1; ++nContigEnd2 ) { if ( ( pCEP->pContig_[ nContigEnd1 ] == pContig[ nContigEnd2 ] && pCEP->nWhichEnd_[ nContigEnd1] == nContigEnd[ nContigEnd2 ] ) ) { bError = true; soErrorMessage += "Problem: there is already a user-defined contigEndPair making the connection: "; soErrorMessage += pCEP->soGetDescription(); soErrorMessage += " "; } } } } for( nContig = 0; nContig <= 1; ++nContig ) { int nOtherEnd = ( nContig == 0 ? 1 : 0 ); Contig* pMyContig = pContig[ nContig ]; int nWhichEnd = nContigEnd[ nContig ]; // pContig, nWhichEnd is connected to // pContig[ nOtherEnd], nContigEnd[ nOtherEnd ] // Let's see if pContig, nWhichEnd is connected to some // other contig or if it is connected to the same contig, // but a different end of it. // We find the contig-end that this contig-end is connected to // by looking in the Contig object: // It is connected to contig pContig->pContig_[ nWhichEnd ], // end: pContig->nWhichEnd_[ nWhichEnd ] // is the contig already connected to anything? If not, // there is no inconsistency. if ( pMyContig->pContig_[ nWhichEnd ] ) { if ( pMyContig->pContig_[ nWhichEnd ] != pContig[ nOtherEnd ] ) { bError = true; contigEndPair* pCEP = pMyContig->pCEP_[ nWhichEnd ]; if ( pCEP ) { soErrorMessage += "Problem: "; if ( pCEP->bUserDefined_ ) { soErrorMessage += "there is already a user-defined contigEndPair making the connection: "; soErrorMessage += pCEP->soGetDescription(); soErrorMessage += " "; } else { soErrorMessage += "there are "; soErrorMessage += RWCString( (long) pCEP->nNumberOfForwardReversePairs_ ); soErrorMessage += " forward/reverse pairs supporting the following connection: "; soErrorMessage += pCEP->soGetDescription(); soErrorMessage += " "; } } else { soErrorMessage += "there is already a connection between "; soErrorMessage += szWhichGap( nWhichEnd ); soErrorMessage += " of "; soErrorMessage += pMyContig->soGetName(); soErrorMessage += " and "; soErrorMessage += szWhichGap( pMyContig->nWhichEnd_[ nWhichEnd ] ); soErrorMessage += " of "; soErrorMessage += pMyContig->pContig_[ nWhichEnd ]->soGetName(); soErrorMessage += " This link was probably inferred from fwd/rev pair links between other contigs and not directly via fwd/rev pairs between these 2 contig ends. "; } } else if ( pMyContig->nWhichEnd_[ nWhichEnd ] != nContigEnd[ nOtherEnd ] ) { bError = true; contigEndPair* pCEP = pMyContig->pCEP_[ nWhichEnd ]; if ( pCEP ) { soErrorMessage += "Problem: "; if ( pCEP->bUserDefined_ ) { soErrorMessage += "there is already a user-defined contigEndPair making the connection: "; soErrorMessage += pCEP->soGetDescription(); soErrorMessage += " Perhaps you meant a different end."; } // note Sept 2004: I don't understand why there is an // error message only in the case of a user-defined // contigEndPair here. Why not also if there are // fwd/rev pairs? } else { soErrorMessage += "Problem: there is already a connection between "; soErrorMessage += szWhichGap( nWhichEnd ); soErrorMessage += " of "; soErrorMessage += pMyContig->soGetName(); soErrorMessage += " and "; soErrorMessage += szWhichGap( pMyContig->nWhichEnd_[ nWhichEnd ] ); soErrorMessage += " of "; soErrorMessage += pMyContig->pContig_[ nWhichEnd ]->soGetName(); soErrorMessage += " This link was probably inferred from fwd/rev pair links between other contigs and not directly via fwd/rev pairs between these 2 contig ends."; } } } // if ( pMyContig->pContig_[ nwhichEnd ] ) { } if ( bError ) { contigEndPair cep2( pContig[0], pContig[1], nContigEnd[0], nContigEnd[1] ); soErrorMessage += " Are you sure you want to make contig-end pair "; soErrorMessage += cep2.soGetDescription(); soErrorMessage += " ?"; if ( !bGuiGetAnswerYesNo( soErrorMessage ) ) { return; } } // put contigEndPair tags on these ends of these contigs // I'm not so sure--shouldn't this be added when the user pushes // "apply" ? It could check which already exist and add the ones // that don't. But if they are added here, that wouldn't be // necessary--it just adds the one the user has asked to add. So // maybe this is the way to go. What does "apply" do then? I // guess it would re-create the contig map. If assembly view is // up, it would pop it down and up again. RWCString soContigEndPairID = pAssembly->soGetNextContigEndPairID(); // must figure out where to put this tag. int nConsPos[2]; tag* pTags[2]; for( nContig = 0; nContig <= 1; ++nContig ) { nConsPos[ nContig ] = pContig[ nContig ]->nGetGoodPlaceForContigEndPairTag( nContigEnd[ nContig ] ); // put the tag on the contig tag* pTag = new tag( NULL, // LocatedFragment pContig[ nContig ], "contigEndPair", nConsPos[ nContig ], nConsPos[ nContig ], false, // bNoTrans "", // soComment soConsed, // "consed" soEmptyString, // current date/time false ); // bNoTrans // save to record in cep pTags[ nContig ] = pTag; int nUnpaddedStart = pContig[ nContig ]->nUnpaddedIndex( nConsPos[ nContig ] ); RWCString soBases; pContig[ nContig ]->getPartOfUnpaddedConsensus( nUnpaddedStart, 10, soBases, ( nContigEnd[ nContig ] == nLeftGap ? true : false ), // bComplemented ( nContigEnd[ nContig ] == nLeftGap ? false : true ) ); // bTowardsIncreasingUnpaddedPositions pTag->soMiscData_ = soContigEndPairID; pTag->soMiscData_ += "\n"; pTag->soMiscData_ += ( nContigEnd[ nContig ] == nLeftGap ? "<-gap" : "gap->" ); pTag->soMiscData_ += "\n"; pTag->soMiscData_ += soBases; EditAction* pEditAction = new editAddConsensusTag( pTag ); ConsEd::pGetConsEd()->doEditAction( pEditAction, true ); // bWriteToEditHistoryFile } // check that the new tag will be correctly interpreted as a contigEndPair aUserDefinedContigEndPairs.clearAndDestroy(); pAssembly->getUserDefinedContigEndPairs( aUserDefinedContigEndPairs ); // here is the contigEndPair we are looking for contigEndPair cep( pContig[0], pContig[1], nContigEnd[0], nContigEnd[1] ); cep.recordTags( pTags[0], pTags[1] ); cep.bUserDefined_ = true; // look for it bool bFound = false; for( nContigEndPair = 0; nContigEndPair < aUserDefinedContigEndPairs.length(); ++nContigEndPair ) { if ( cep == *aUserDefinedContigEndPairs[ nContigEndPair ] ) { bFound = true; break; } } if ( !bFound ) { // what shall we do? Cry? Warn the user, at least. RWCString soError = "Sorry--for some reason, I can't find the contigEndPair you just made. This may be a bug."; popupErrorMessage2( widPopupShell_, soError.data() ); return; } RWCString soDescription = cep.soGetDescription(); XmString xms = XmStringCreateLocalized( soDescription.data() ); XmListAddItem( widContigEndPairList_, xms, 0 ); XmStringFree( xms ); aContigEndPairs_.insert( cep ); restartAssemblyView(); } void guiReorderContigs :: setExistingUserDefinedContigEndPairs() { RWTPtrOrderedVector aUserDefinedContigEndPairs; ConsEd::pGetAssembly()->getUserDefinedContigEndPairs( aUserDefinedContigEndPairs ); // in case there is any item left and the list is going to // length zero, in which case it will not be reset XmListDeleteAllItems( widContigEndPairList_ ); if ( aUserDefinedContigEndPairs.length() == 0 ) return; XmStringTable ppXtString = (XmStringTable) XtMalloc( aUserDefinedContigEndPairs.length() * sizeof( XmString ) ); aContigEndPairs_.clear(); aContigEndPairs_.resize( aUserDefinedContigEndPairs.length() ); int nContigEndPair; for( nContigEndPair = 0; nContigEndPair < aUserDefinedContigEndPairs.length(); ++nContigEndPair ) { contigEndPair* pContigEndPair = aUserDefinedContigEndPairs[ nContigEndPair ]; RWCString soDescription = pContigEndPair->soGetDescription(); ppXtString[ nContigEndPair ] = XmStringCreateLocalized( soDescription.data() ); aContigEndPairs_.insert( *pContigEndPair ); } XtVaSetValues( widContigEndPairList_, XmNitems, ppXtString, XmNitemCount, aUserDefinedContigEndPairs.length(), NULL ); // free all the memory used for the array of XmString for( nContigEndPair = 0; nContigEndPair < aUserDefinedContigEndPairs.length(); ++nContigEndPair ) { XmStringFree( ppXtString[ nContigEndPair ] ); } XtFree( (char*) ppXtString ); aUserDefinedContigEndPairs.clearAndDestroy(); } void guiReorderContigs :: userPushedDelete() { int* pPositionList; int nNumberOfSelectedItems = 0; if ( !XmListGetSelectedPos( widContigEndPairList_, &pPositionList, &nNumberOfSelectedItems ) || nNumberOfSelectedItems == 0 ) { popupErrorMessage2( widPopupShell_, "First select the contig end pair and then click \"Delete Selected\"" ); return; } assert( nNumberOfSelectedItems == 1 ); int nZeroBasedIndex = pPositionList[0] - 1; contigEndPair& cep = aContigEndPairs_[ nZeroBasedIndex ]; for( int nTag = 0; nTag <= 1; ++nTag ) { tag* pTag = cep.pTag_[ nTag ]; EditAction* pEditAction = new editDeleteConsensusTag( pTag ); ConsEd::pGetConsEd()->doEditAction( pEditAction, true ); // write to edit history file } restartAssemblyView(); } void guiReorderContigs :: raiseWindow() { XtMapWidget( widPopupShell_ ); XRaiseWindow( XtDisplay( widPopupShell_ ), XtWindow( widPopupShell_ ) ); }