/***************************************************************************** # 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 "miniassembly.h" #include #include #include #include #include #include #include #include #include #include "popupErrorMessage2.h" #include "popupErrorMessage.h" #include "guiapp.h" #include "handleWindowManagerDelete2.h" #include "hp_exception_kludge.h" #include "assembly.h" #include "consed.h" #include "filGetUniqueFilename.h" #include "consedParameters.h" #include "soGetErrno.h" #include "popupInfoMessage.h" #include "bIsNumeric.h" #include "guiMultiContigNavigator.h" #include "bGuiGetAnswerYesNo.h" #include "nCompareContigsByName.h" #include #include #include #include "rwctokenizer.h" #include "bIsNumericMaybeWithWhitespace.h" #include "intXtPointerUnion.h" #include "textbox.h" #include "phdBall2Fasta.h" static void cbClearHighlightedContigsInRightListButton( Widget wid, XtPointer pClientData, XtPointer pCallData ) { miniassembly* pMiniassembly = (miniassembly*) pClientData; TRY_CATCH_WRAPPER( pMiniassembly->userPressedClearHighlightedContigsInRightListButton() ); } static void cbClearRightListButton( Widget wid, XtPointer pClientData, XtPointer pCallData ) { miniassembly* pMiniassembly = (miniassembly*) pClientData; TRY_CATCH_WRAPPER( pMiniassembly->userPressedClearRightListButton() ); } static void cbCancelButton( Widget wid, XtPointer pClientData, XtPointer pCallData ) { miniassembly* pMiniassembly = (miniassembly*) pClientData; TRY_CATCH_WRAPPER( delete pMiniassembly; ); } static void cbReassembleButton( Widget wid, XtPointer pClientData, XtPointer pCallData ) { miniassembly* pMiniassembly = (miniassembly*) pClientData; TRY_CATCH_WRAPPER( pMiniassembly->userPushedReassembleButton() ); } static void cbMoveHighlightedToRight( Widget wid, XtPointer pClientData, XtPointer pCallData ) { miniassembly* pMiniassembly = (miniassembly*) pClientData; TRY_CATCH_WRAPPER( pMiniassembly->userPushedMoveHighlightedToRight() ); } miniassembly :: miniassembly() : bPutEachSingletIntoItsOwnContig_( false ) { aContigsToReassemble_.soName_ = "miniassembly::aContigsToReassemble_"; aReadsToReassemble_.soName_ = "miniassembly::aReadsToReassemble_"; } void miniassembly :: createWindow() { widPopupShell_ = XtVaCreatePopupShell( "miniassembly", topLevelShellWidgetClass, GAPP->widGetTopLevel(), XmNtitle, "Reassemble Some Contigs", XmNnoResize, False, XmNtransient, False, XmNdeleteResponse, XmDO_NOTHING, NULL ); handleWindowManagerDelete2( widPopupShell_, cbCancelButton, this ); Widget widForm = XtVaCreateManagedWidget( "form", xmFormWidgetClass, widPopupShell_, XmNshadowThickness, 0, XmNborderWidth, 0, NULL ); Widget widAllContigsLabel = XtVaCreateManagedWidget( "All Contigs:", xmLabelWidgetClass, widForm, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 20, XmNleftAttachment, XmATTACH_FORM, XmNbottomOffset, 0, NULL ); Widget widContigsToReassembleLabel = XtVaCreateManagedWidget( "Contigs to Reassemble:", xmLabelWidgetClass, widForm, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 20, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50, XmNbottomOffset, 0, NULL ); Widget widConnectToWidgetOnTop = widContigsToReassembleLabel; // now build up widgets from the bottom of the window widReassembleButton_ = XtVaCreateManagedWidget( "Reassemble", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 20, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 40, NULL ); XtAddCallback( widReassembleButton_, XmNactivateCallback, cbReassembleButton, this ); Widget widCancelButton = XtVaCreateManagedWidget( "Cancel", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, widReassembleButton_, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 60, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 80, NULL ); XtAddCallback( widCancelButton, XmNactivateCallback, cbCancelButton, this ); Widget widConnectToWidgetOnBottom = widReassembleButton_; Widget widRadioBox = XmCreateRadioBox( widForm, "radio", NULL, 0 ); XtVaSetValues( widRadioBox, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNbottomOffset, 20, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNorientation, XmHORIZONTAL, NULL ); widConnectToWidgetOnBottom = widRadioBox; widPutIntoSeparateContigs_ = XtVaCreateManagedWidget( "Put into separate contigs", xmToggleButtonWidgetClass, widRadioBox, XmNset, True, // default NULL ); Widget widDiscard = XtVaCreateManagedWidget( "Discard from assembly", xmToggleButtonWidgetClass, widRadioBox, XmNset, False, NULL ); XtManageChild( widRadioBox ); Widget widWhatToDoWithSinglets = XtVaCreateManagedWidget( "What to do with miniassembly singlet reads:", xmLabelWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, NULL ); widConnectToWidgetOnBottom = widWhatToDoWithSinglets; Widget widPhrapOptionsLabel = XtVaCreateManagedWidget( "other phrap options:", xmLabelWidgetClass, widForm, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, NULL ); Dimension dimWidth; XtVaGetValues( widPhrapOptionsLabel, XmNwidth, &dimWidth, NULL ); widOtherPhrapOptions_ = XtVaCreateManagedWidget( "phrap options", xmTextFieldWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNbottomOffset, 20, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, dimWidth + 10, NULL ); XtVaSetValues( widPhrapOptionsLabel, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, widOtherPhrapOptions_, XmNbottomWidget, widOtherPhrapOptions_, NULL ); widConnectToWidgetOnBottom = widOtherPhrapOptions_; Widget widMinScoreLabel = XtVaCreateManagedWidget( "-minscore ", xmLabelWidgetClass, widForm, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, NULL ); XtVaGetValues( widMinScoreLabel, XmNwidth, &dimWidth, NULL ); widMinScore_ = XtVaCreateManagedWidget( "minscore", xmTextFieldWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, dimWidth + 10, XmNcolumns, 4, NULL ); XtVaSetValues( widMinScoreLabel, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, widMinScore_, XmNbottomWidget, widMinScore_, NULL ); Widget widMinMatchLabel = XtVaCreateManagedWidget( "-minmatch", xmLabelWidgetClass, widForm, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widMinScore_, XmNleftOffset, 20, NULL ); XtVaGetValues( widMinMatchLabel, XmNwidth, &dimWidth, NULL ); widMinMatch_ = XtVaCreateManagedWidget( "minmatch", xmTextFieldWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widMinScore_, XmNleftOffset, 20 + dimWidth + 10, XmNcolumns, 4, NULL ); XtVaSetValues( widMinMatchLabel, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, widMinMatch_, XmNbottomWidget, widMinMatch_, NULL ); Widget widForceLevelLabel = XtVaCreateManagedWidget( "-forcelevel", xmLabelWidgetClass, widForm, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widMinMatch_, XmNleftOffset, 20, NULL ); XtVaGetValues( widForceLevelLabel, XmNwidth, &dimWidth, NULL ); widForceLevel_ = XtVaCreateManagedWidget( "forcelevel", xmTextFieldWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widMinMatch_, XmNleftOffset, 20 + dimWidth + 10, XmNcolumns, 4, NULL ); XtVaSetValues( widForceLevelLabel, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, widForceLevel_, XmNbottomWidget, widForceLevel_, NULL ); widConnectToWidgetOnBottom = widForceLevel_; Widget widClearHighlighted = XtVaCreateManagedWidget( "Clear Highlighted", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 60, NULL ); XtAddCallback( widClearHighlighted, XmNactivateCallback, cbClearHighlightedContigsInRightListButton, this ); widConnectToWidgetOnBottom = widClearHighlighted; Widget widMoveHighlightedToRight = XtVaCreateManagedWidget( "Move Highlighted To Right", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, NULL ); XtAddCallback( widMoveHighlightedToRight, XmNactivateCallback, cbMoveHighlightedToRight, this ); Widget widClearList = XtVaCreateManagedWidget( "Clear List", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widConnectToWidgetOnBottom, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 60, NULL ); XtAddCallback( widClearList, XmNactivateCallback, cbClearRightListButton, this ); widConnectToWidgetOnBottom = widMoveHighlightedToRight; const int nVisibleItemCount = 20; int nArgs; Arg aArg[50]; nArgs = 0; XtSetArg( aArg[ nArgs ], XmNtopAttachment, XmATTACH_WIDGET ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNtopWidget, widConnectToWidgetOnTop ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNtopOffset, 10 ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNbottomAttachment, XmATTACH_WIDGET ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNbottomWidget, widConnectToWidgetOnBottom ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNbottomOffset, 10 ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNleftAttachment, XmATTACH_FORM ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNrightAttachment, XmATTACH_POSITION ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNrightPosition, 45 ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNvisibleItemCount, nVisibleItemCount ); ++nArgs; XtSetArg( aArg[nArgs], XmNselectionPolicy, XmEXTENDED_SELECT); nArgs++; widAllContigs_ = XmCreateScrolledList( widForm, "all_contigs", aArg, nArgs ); XtManageChild( widAllContigs_ ); nArgs = 0; XtSetArg( aArg[ nArgs ], XmNtopAttachment, XmATTACH_WIDGET ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNtopWidget, widConnectToWidgetOnTop ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNtopOffset, 10 ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNbottomAttachment, XmATTACH_WIDGET ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNbottomWidget, widConnectToWidgetOnBottom ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNbottomOffset, 10 ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNleftAttachment, XmATTACH_POSITION ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNleftPosition, 50 ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNrightAttachment, XmATTACH_FORM ); ++nArgs; XtSetArg( aArg[ nArgs ], XmNvisibleItemCount, nVisibleItemCount ); ++nArgs; XtSetArg( aArg[nArgs], XmNselectionPolicy, XmEXTENDED_SELECT); nArgs++; widContigsToReassemble_ = XmCreateScrolledList( widForm, "contigs_to_reassemble", aArg, nArgs ); XtManageChild( widContigsToReassemble_ ); putContigsInLeftContigsList(); putContigsInRightContigsList(); XtPopup( widPopupShell_, XtGrabNone ); } miniassembly :: ~miniassembly() { XtPopdown( widPopupShell_ ); XtDestroyWidget( widPopupShell_ ); } void miniassembly :: putContigsInLeftContigsList() { Assembly* pAssembly = ConsEd::pGetAssembly(); XmStringTable xmStringList = (XmStringTable) XtMalloc( pAssembly->nNumContigs() * sizeof( XmString * ) ); RWCString soLineToDisplay( (size_t) 100 ); int nContig; for( nContig= 0; nContig < pAssembly->nNumContigs(); ++nContig ) { Contig* pContig = pAssembly->pGetContig( nContig ); soLineToDisplay = pContig->soGetFancyName(); int nNumberOfReads = pContig->nGetNumberOfFragsInContig(); if ( nNumberOfReads == 1 ) { soLineToDisplay += ": "; LocatedFragment* pLocFrag = pContig->pLocatedFragmentGet( 0 ); soLineToDisplay += pLocFrag->soGetName(); } else { int nContigLength = pContig->nGetUnpaddedSeqLength(); soLineToDisplay.increaseMaxLengthIfNecessary( 100 ); soLineToDisplay.appendFormat( " (%d reads, %d bps)", nNumberOfReads, nContigLength ); } xmStringList[nContig] = XmStringCreateSimple( soLineToDisplay.data() ); } XtVaSetValues( widAllContigs_, XmNitems, xmStringList, XmNitemCount, pAssembly->nNumContigs(), XmNtopItemPosition, pAssembly->nNumContigs(), NULL ); // free all the allocated memory for( nContig = 0; nContig < pAssembly->nNumContigs(); ++nContig ) { XmStringFree( xmStringList[ nContig ] ); } XtFree( (char*) xmStringList ); } void miniassembly :: putContigsInRightContigsList() { for( int nContig = 0; nContig < pCP->aListOfContigNamesForMiniassembly_.length(); ++nContig ) { RWCString soContigName = pCP->aListOfContigNamesForMiniassembly_[ nContig ]; Contig* pContig = ConsEd::pGetAssembly()->pGetContigByName( soContigName ); if ( pContig ) { aContigsToReassemble_.insert( pContig ); } } refreshRightList(); } void miniassembly :: userPushedMoveHighlightedToRight() { // which reads are highlighted? int* pPositionList; int nNumberOfSelectedItems; if ( !XmListGetSelectedPos( widAllContigs_, &pPositionList, &nNumberOfSelectedItems ) ) { nNumberOfSelectedItems = 0; } if ( nNumberOfSelectedItems == 0 ) { popupErrorMessage2( widPopupShell_, "You must select the contigs you want to move to the right list. See instructions by clicking on 'help'" ); XtFree( (char*) pPositionList ); return; } for( int nSelectedContig = 0; nSelectedContig < nNumberOfSelectedItems; ++nSelectedContig ) { int nOneBasedInXmList = pPositionList[ nSelectedContig ]; // convert to zero-based, which is the index of Assembly::pGetContig Contig* pContig = ConsEd::pGetAssembly()->pGetContig( nOneBasedInXmList - 1 ); // add this to the right list aContigsToReassemble_.insert( pContig ); } refreshRightList(); } void miniassembly :: refreshRightList() { XmStringTable xmStringList = (XmStringTable) XtMalloc( aContigsToReassemble_.length() * sizeof( XmString * ) ); RWCString soLineToDisplay( (size_t) 100 ); int nContig; for( nContig = 0; nContig < aContigsToReassemble_.length(); ++nContig ) { Contig* pContig = aContigsToReassemble_[ nContig ]; soLineToDisplay = pContig->soGetFancyName(); int nNumberOfReads = pContig->nGetNumberOfFragsInContig(); if ( nNumberOfReads == 1 ) { soLineToDisplay += ": "; LocatedFragment* pLocFrag = pContig->pLocatedFragmentGet( 0 ); soLineToDisplay += pLocFrag->soGetName(); } else { int nContigLength = pContig->nGetUnpaddedSeqLength(); soLineToDisplay.increaseMaxLengthIfNecessary( 100 ); soLineToDisplay.appendFormat( " (%d reads, %d bps)", nNumberOfReads, nContigLength ); } xmStringList[nContig] = XmStringCreateSimple( soLineToDisplay.data() ); } XtVaSetValues( widContigsToReassemble_, XmNitems, xmStringList, XmNitemCount, aContigsToReassemble_.length(), XmNtopItemPosition, aContigsToReassemble_.length(), NULL ); // free all the allocated memory for( nContig = 0; nContig < aContigsToReassemble_.length(); ++nContig ) { XmStringFree( xmStringList[ nContig ] ); } XtFree( (char*) xmStringList ); } void miniassembly :: userPressedClearRightListButton() { aContigsToReassemble_.clear(); refreshRightList(); } void miniassembly :: userPressedClearHighlightedContigsInRightListButton() { // which contigs are highlighted? int* pPositionList; int nNumberOfSelectedItems; if ( !XmListGetSelectedPos( widContigsToReassemble_, &pPositionList, &nNumberOfSelectedItems ) ) { nNumberOfSelectedItems = 0; } if ( nNumberOfSelectedItems == 0 ) { popupErrorMessage2( widPopupShell_, "You must first select the contigs you want to remove from the right list. See instructions by clicking on 'help'" ); XtFree( (char*) pPositionList ); return; } // must go in reverse order or else bug in that the list positions // will have changed and the list position is no longer nOneBasedInXmList - 1 for( int nSelectedContig = nNumberOfSelectedItems - 1; nSelectedContig >= 0; --nSelectedContig ) { int nOneBasedInXmList = pPositionList[ nSelectedContig ]; // convert to zero-based, which is the index of aContigsToReassemble_ aContigsToReassemble_.removeAt( nOneBasedInXmList - 1 ); } refreshRightList(); } void miniassembly :: userPushedReassembleButton() { Assembly* pAssembly = ConsEd::pGetAssembly(); if ( aContigsToReassemble_.length() == 0 ) { popupErrorMessage2( widPopupShell_, "You have not specified any contigs to be reassembled. Do so by adding contigs to the right list." ); return; } if ( !bUserEnteredFieldsAreOK() ) return; if ( !bPhredPhrapVersionIsOK() ) return; if ( pAssembly->bChanged() ) { popupErrorMessage2( widPopupShell_, "You must first save the assembly before making a miniassembly" ); return; } // I'm concerned that there may be duplicate contigs in the right list // So sort them and eliminate dupicates qsort( aContigsToReassemble_.data(), aContigsToReassemble_.length(), sizeof( Contig* ), ( (int(*) (const void*, const void* ) ) nCompareContigsByName ) ); // nCmpContigsByName is in assembly3.cpp // remove duplicates bool bDuplicatesRemoved = false; RWCString soMessage = "removed duplicate contigs: "; int nContig; for( nContig = aContigsToReassemble_.length() - 1; nContig >= 1; --nContig ) { Contig* pContigBefore = aContigsToReassemble_[ nContig - 1 ]; Contig* pContigAfter = aContigsToReassemble_[ nContig ]; if ( pContigBefore == pContigAfter ) { soMessage += pContigAfter->soGetName(); soMessage += " "; bDuplicatesRemoved = true; aContigsToReassemble_.removeAt( nContig ); } } if ( bDuplicatesRemoved ) { popupInfoMessage( widPopupShell_, soMessage ); } // now keep a list of reads that are to be reassembled--this will be // useful to see if any of these reads are in singlets int nNumberOfReadsToReassemble = 0; for( nContig = 0; nContig < aContigsToReassemble_.length(); ++nContig ) { Contig* pContig = aContigsToReassemble_[ nContig ]; nNumberOfReadsToReassemble += pContig->nGetNumberOfFragsInContig(); } RWCString soMiniProjectName = filGetUniqueFilename( "mini" ); FileName filFastaFileOfReads = soMiniProjectName + ".fasta.screen"; FileName filFastaQual = filFastaFileOfReads + ".qual"; FILE* pFasta = fopen( filFastaFileOfReads.data(), "w" ); if ( !pFasta ) { THROW_FILE_ERROR( filFastaFileOfReads ); } FILE* pQual = fopen( filFastaQual.data(), "w" ); if ( !pQual ) { THROW_FILE_ERROR( filFastaQual ); } RWTValSortedVector aPhdBallsNeeded; for( nContig = 0; nContig < aContigsToReassemble_.length(); ++nContig ) { Contig* pContig = aContigsToReassemble_[ nContig ]; for( int nRead = 0; nRead < pContig->nGetNumberOfFragsInContig(); ++nRead ) { LocatedFragment* pLocFrag = pContig->pLocatedFragmentGet( nRead ); if ( ! pLocFrag->filPhdBall_.isNull() ) { FileName filPhdBall = pLocFrag->filPhdBall_; if ( ! aPhdBallsNeeded.bContains( filPhdBall ) ) { aPhdBallsNeeded.insert( filPhdBall ); } } pLocFrag->writeReadToFasta( pFasta, pQual, false ); // bUseSeqPhredCalledBases --use edited bases } } fclose( pFasta ); fclose( pQual ); // write file of phd balls FileName filPhdBallsNeeded = soMiniProjectName + ".phdballs.fof"; FILE* pPhdBalls = fopen( filPhdBallsNeeded.data(), "w" ); if ( !pPhdBalls ) { THROW_FILE_ERROR( filPhdBallsNeeded ); } for( int nPhdBall = 0; nPhdBall < aPhdBallsNeeded.length(); ++nPhdBall ) { if ( aPhdBallsNeeded[ nPhdBall ] == "phd.ball" ) { fprintf( pPhdBalls, "phd.ball\n" ); } else { FileName filPhdBallFullPath = pCP->filPhdBallDirectory_ + "/" + aPhdBallsNeeded[ nPhdBall ]; fprintf( pPhdBalls, "%s\n", filPhdBallFullPath.data() ); } } fclose( pPhdBalls ); RWCString soCommand = pCP->filFullPathnameOfMiniassemblyScript_; soCommand += " "; soCommand += soMiniProjectName; soCommand += " -miniassembly"; soCommand += " -phdballs "; soCommand += filPhdBallsNeeded; soCommand += " -file_with_new_ace_file_name "; FileName filLookHereForAceFileName = filGetUniqueFilename( "mini" ) + ".fof"; soCommand += filLookHereForAceFileName; soCommand += " -ace_file_with_consensus_tags "; soCommand += pAssembly->soGetAceFileName(); soCommand += " "; soCommand += soPhrapOptions_; // run phredPhrap cerr << "running: " << soCommand << endl; runCommandAndCreateTerminateButton( soCommand ); // now comes the hard part--integrating the 2 assemblies // what is the name of the new ace file? The answer is in // filLookHereForAceFileName FILE* pFOF = fopen( filLookHereForAceFileName.data(), "r" ); if ( !pFOF ) { RWCString soErrorMessage = "phredPhrap was supposed to put the name of the new ace file in a file called "; soErrorMessage += filLookHereForAceFileName; soErrorMessage += ". However, this file cannot be opened. Thus we cannot merge this new assembly."; popupErrorMessage2( widPopupShell_, soErrorMessage.data() ); return; } const int nMaxLineSize = 200; char szAceFileName[ nMaxLineSize + 1]; if ( fgets( szAceFileName, nMaxLineSize, pFOF ) == NULL ) { RWCString soErrorMessage = "The file "; soErrorMessage += filLookHereForAceFileName; soErrorMessage += " was supposed to contain the name of the new ace file but instead it is empty. (If you terminated the assembly, that would be the cause, so don't worry.)"; popupErrorMessage2( widPopupShell_, soErrorMessage.data() ); return; } fclose( pFOF ); RWCString soNewAceFileName( szAceFileName ); // I think there is a \n at the end of it, so cut that off. soNewAceFileName.stripTrailingWhitespaceFast(); // just in case the user is using a custom phredPhrap script that // puts in leading whitespace soNewAceFileName = soNewAceFileName.stripWhitespace( RWCString::LEADING ); Assembly *pMiniAssembly = new Assembly( soNewAceFileName, false ); // bSetGlobalAssembly int nNumberOfRowsNeeded = pMiniAssembly->nNumContigs() + 6; if ( nNumberOfRowsNeeded > 20 ) nNumberOfRowsNeeded = 20; TextBox* pTextBox = new TextBox( "Miniassembly Contigs", nNumberOfRowsNeeded ); for( nContig = 0; nContig < pMiniAssembly->nNumContigs(); ++nContig ) { Contig* pContig = pMiniAssembly->pGetContig( nContig ); RWCString soLine = "one contig with " + RWCString( (long) pContig->nGetNumberOfFragsInContig() ) + " reads\n"; pTextBox->append( soLine ); } pTextBox->makeVisible(); RWCString soQuestion( (size_t) 1000 ); soQuestion = "new miniassembly contains "; soQuestion += RWCString( (long) pMiniAssembly->nNumContigs() ); soQuestion += " contig(s) as in other box that just popped up\n"; soQuestion += "Are you finished mini-assembling these contigs? (yes) (If you answer \"no\", you may reassemble them again.)"; if ( !bGuiGetAnswerYesNo( soQuestion ) ) { delete pMiniAssembly; return; } // if don't do this, get segmentation fault because the // template arrays will no longer be valid but assemblyView (et al) // will try to use them ConsEd::pGetConsEd()->whatToDoBeforeModifyAssembly(); // compare the new list of reads to the old to see if they are the same // first count the number of reads in the new assembly int nNumberOfReadsInNewAssembly = 0; for( nContig = 0; nContig < pMiniAssembly->nNumContigs(); ++nContig ) { Contig* pContig = pMiniAssembly->pGetContig( nContig ); nNumberOfReadsInNewAssembly += pContig->nGetNumberOfFragsInContig(); } readsSortedByReadName aReadsInNewAssembly( (size_t) nNumberOfReadsInNewAssembly ); aReadsInNewAssembly.soName_ = "miniassembly::aReadsInNewAssembly"; for( nContig = 0; nContig < pMiniAssembly->nNumContigs(); ++nContig ) { Contig* pContig = pMiniAssembly->pGetContig( nContig ); for( int nRead = 0; nRead < pContig->nGetNumberOfFragsInContig(); ++nRead ) { LocatedFragment* pLocFrag = pContig->pLocatedFragmentGet( nRead ); aReadsInNewAssembly.insert( pLocFrag ); } } aReadsToReassemble_.resize( nNumberOfReadsToReassemble ); for( nContig = 0; nContig < aContigsToReassemble_.length(); ++nContig ) { Contig* pContig = aContigsToReassemble_[ nContig ]; for( int nRead = 0; nRead < pContig->nGetNumberOfFragsInContig(); ++nRead ) { LocatedFragment* pLocFrag = pContig->pLocatedFragmentGet( nRead ); aReadsToReassemble_.insert( pLocFrag ); } } LocatedFragment* pSentinelLocFrag = new LocatedFragment( RWCString( (char) 255 ), // name 0, // nConsensusStartPos, false, // bIsComp NULL ); // pContig aReadsInNewAssembly.insert( pSentinelLocFrag ); aReadsToReassemble_.insert( pSentinelLocFrag ); aReadsToReassemble_.resort(); aReadsInNewAssembly.resort(); // now compare the lists RWTPtrOrderedVector aSingletsInMiniassembly; int nReadInNewAssembly = 0; int nReadInOldAssembly = 0; RWCString soErrorMessage; while( nReadInNewAssembly < aReadsInNewAssembly.length() && nReadInOldAssembly < aReadsToReassemble_.length() ) { if ( aReadsInNewAssembly[ nReadInNewAssembly ]->soGetName() < aReadsToReassemble_[ nReadInOldAssembly ]->soGetName() ) { soErrorMessage += "Program bug since there is a read in the new assembly that was not in the original assembly: "; soErrorMessage += aReadsInNewAssembly[ nReadInNewAssembly ]->soGetName(); soErrorMessage += "\n"; ++nReadInNewAssembly; } else if ( aReadsInNewAssembly[ nReadInNewAssembly ]->soGetName() > aReadsToReassemble_[ nReadInOldAssembly ]->soGetName() ) { // I think no error message about these--we are usually dealing with // them by putting them into their own contigs. 3/03 // soErrorMessage += "Read "; // soErrorMessage += aReadsToReassemble_[ nReadInOldAssembly ]->soGetName(); // soErrorMessage += " is not found in the new assembly. It must be in the singlets file meaning phrap did find significant overlap between it and other reads.\n"; aSingletsInMiniassembly.insert( aReadsToReassemble_[ nReadInOldAssembly ] ); ++nReadInOldAssembly; } else if ( aReadsInNewAssembly[ nReadInNewAssembly ]->soGetName() == aReadsToReassemble_[ nReadInOldAssembly ]->soGetName() ) { ++nReadInNewAssembly; ++nReadInOldAssembly; } else { // we should have covered all the cases above assert( false ); } } if ( !soErrorMessage.isNull() ) { // must attach this to the main window since the miniassembly // window is going away popupErrorMessage( soErrorMessage.data() ); } // get rid of the sentinel aReadsToReassemble_.removeLast(); aReadsInNewAssembly.removeLast(); // optionally, put all singlets into their own contigs RWTPtrOrderedVector aSingletContigs; if ( bPutEachSingletIntoItsOwnContig_ ) { cerr << "putting singlets into own contigs..."; cerr.flush(); aSingletContigs.resize( aSingletsInMiniassembly.length() ); for( int nSinglet = 0; nSinglet < aSingletsInMiniassembly.length(); ++nSinglet ) { LocatedFragment* pLocFrag = aSingletsInMiniassembly[ nSinglet ]; Contig* pOldContig = pLocFrag->pContig_; // remove this read from the old contig. this is // important so that the read isn't deleted when the contig // is deleted (below) but still used in a new contig. pOldContig->apLocatedFragment_.remove( pLocFrag ); // make a new contig out of it: // This is given a name that is consistent with others in the // main assembly and is moved into the main assembly. Contig* pNewContig = pLocFrag->pMakeAContigOutOfThisRead(); aSingletContigs.insert( pNewContig ); } cerr << "done" << endl; cerr.flush(); } // now delete the old contigs/reads from the assembly for( nContig = 0; nContig < aContigsToReassemble_.length(); ++nContig ) { Contig* pContig = aContigsToReassemble_[ nContig ]; for( int nRead = 0; nRead < pContig->nGetNumberOfFragsInContig(); ++nRead ) { LocatedFragment* pLocFrag = pContig->pLocatedFragmentGet( nRead ); delete pLocFrag; } // this doesn't delete the reads delete pContig; } // now we do not need to create the contigs since they are already created. // We need to rename them so they do not conflict with the names of the // existing contigs. Then we will remove the pMiniassembly, but not // the contigs within it. Probably the best way to do that would // be to remove all contig pointers from it and then delete pMiniassembly. // renaming contigs and moving them over Assembly* pMainAssembly = ConsEd::pGetAssembly(); for( nContig = 0; nContig < pMiniAssembly->nNumContigs(); ++nContig ) { Contig* pContig = pMiniAssembly->pGetContig( nContig ); pContig->soSequenceName_ = pMainAssembly->soGetNewContigName(); // put the contig in the new Assembly pMainAssembly->addContig( pContig ); } // load saved list of contigs pCP->aListOfContigNamesForMiniassembly_.clear(); // for the purpose of the gotolist, add the singlet contigs to // pMiniAssembly for( int nSinglet = 0; nSinglet < aSingletContigs.length(); ++nSinglet ) { Contig* pContig = aSingletContigs[ nSinglet ]; pMiniAssembly->addContig( pContig ); } // now make gotolist // put up a navigation box with the new contigs: gotoList* pGotoList = new gotoList(); RWCString soDescription( (size_t) 1000 ); for( nContig = 0; nContig < pMiniAssembly->nNumContigs(); ++nContig ) { Contig* pContig = pMiniAssembly->pGetContig( nContig ); soDescription = pContig->soGetFancyName(); int nNumberOfReads = pContig->nGetNumberOfFragsInContig(); if ( nNumberOfReads == 1 ) { soDescription += ": "; LocatedFragment* pLocFrag = pContig->pLocatedFragmentGet( 0 ); soDescription += pLocFrag->soGetName(); } else { int nContigLength = pContig->nGetUnpaddedSeqLength(); soDescription.increaseMaxLengthIfNecessary( 100 ); soDescription.appendFormat( " (%d reads, %d bps)", nNumberOfReads, nContigLength ); } gotoItem* pGotoItem = new gotoItem( pContig, NULL, // pLocFrag 1, // nStart 1, // nEnd 1, // nUnpaddedStart 1, // nUnpaddedEnd soDescription, false, // bPrefixContigToDescription NULL ); // pOtherData pGotoList->addToList( pGotoItem ); } guiMultiContigNavigator* pGuiNav = new guiMultiContigNavigator( "New Contigs", "", "", 50, "", NULL, NULL, NULL, // widTopLevelShellToBeConnectedTo pGotoList, NULL ); // pContigWin pGuiNav->scrollDownToBottom(); // this does not delete the contigs--just the array delete pMiniAssembly; // do not allow user to try to run this again delete this; ConsEd::pGetConsEd()->updateContigListOnMainConsedWindow(); pMainAssembly->setChanged(); ConsEd::pGetConsEd()->disallowUndos(); } bool miniassembly :: bUserEnteredFieldsAreOK() { soPhrapOptions_ = ""; char* szMinScore = XmTextFieldGetString( widMinScore_ ); RWCString soMinScore( szMinScore ); XtFree( szMinScore ); soMinScore = soMinScore.stripWhitespace( RWCString::BOTH ); if ( !soMinScore.isNull() ) { if ( ! bIsNumeric( soMinScore ) ) { popupErrorMessage2( widPopupShell_, "The -minscore box must either be left empty or else must have a whole number but instead it has %s\n", soMinScore.data() ); return( false ); } soPhrapOptions_ += "-minscore "; soPhrapOptions_ += soMinScore; soPhrapOptions_ += " "; } char* szMinMatch = XmTextFieldGetString( widMinMatch_ ); RWCString soMinMatch( szMinMatch ); XtFree( szMinMatch ); soMinMatch = soMinMatch.stripWhitespace( RWCString::BOTH ); if ( ! soMinMatch.isNull() ) { if ( ! bIsNumeric( soMinMatch ) ) { popupErrorMessage2( widPopupShell_, "The -minmatch box must either be left empty or else must have a whole number but instead it has %s\n", soMinMatch.data() ); return( false ); } soPhrapOptions_ += "-minmatch "; soPhrapOptions_ += soMinMatch; soPhrapOptions_ += " "; } char* szForceLevel = XmTextFieldGetString( widForceLevel_ ); RWCString soForceLevel( szForceLevel ); XtFree( szForceLevel ); soForceLevel = soForceLevel.stripWhitespace( RWCString::BOTH ); if ( ! soForceLevel.isNull() ) { if ( ! bIsNumeric( soForceLevel ) ) { popupErrorMessage2( widPopupShell_, "The -forcelevel box must either be left empty or else must have a whole number but instead it has %s\n", soForceLevel.data() ); return( false ); } soPhrapOptions_ += "-forcelevel "; soPhrapOptions_ += soForceLevel; soPhrapOptions_ += " "; } char* szOtherPhrapOptions = XmTextFieldGetString( widOtherPhrapOptions_ ); soPhrapOptions_ += szOtherPhrapOptions; XtFree( szOtherPhrapOptions ); soPhrapOptions_ += " "; bPutEachSingletIntoItsOwnContig_ = ( XmToggleButtonGetState( widPutIntoSeparateContigs_ ) == True ? true : false ); return( true ); } bool miniassembly :: bPhredPhrapVersionIsOK() { // need to run phredPhrap -v from a pipe so we can read the output if ( pCP->filFullPathnameOfMiniassemblyScript_.index( "phredPhrap" ) == RW_NPOS ) { // the user has their own script, so no way to check versions return( true ); } RWCString soCommand = pCP->filFullPathnameOfMiniassemblyScript_ + " -V"; FILE* pPipe = popen( soCommand.data(), "r" ); if ( !pPipe ) { RWCString soErrorMessage = "could not open pipe to process running "; soErrorMessage += soCommand; soErrorMessage += " "; soErrorMessage += soGetErrno(); popupErrorMessage( soErrorMessage ); // we will try again running phredPhrap above return( true ); } const int nMaxLineSize = 500; char szLine[ nMaxLineSize + 1 ]; if ( fgets( szLine, nMaxLineSize, pPipe ) == NULL ) { RWCString soErrorMessage = "opened pipe to process running "; soErrorMessage += soCommand; soErrorMessage += " but could not read anything from the pipe"; popupErrorMessage( soErrorMessage ); // we will try again running phredPhrap above return( true ); } pclose( pPipe ); RWCString soRequiredVersion( "080818" ); RWCString soVersion( szLine ); soVersion.stripTrailingWhitespaceFast(); if ( soVersion >= soRequiredVersion && soVersion <= "800000" ) { cerr << "Using phredPhrap version " << soVersion << " --good." << endl; return( true ); } else { RWCString soErrorMessage = "To run miniassemblies, you must have phredPhrap version "; soErrorMessage += soRequiredVersion; soErrorMessage += " or better. Instead you have version "; soErrorMessage += soVersion; soErrorMessage += " The phredPhrap script is part of the Consed distribution which you can get from www.phrap.org"; popupErrorMessage( soErrorMessage ); return( false ); } } void miniassembly :: runCommandAndCreateTerminateButton( const RWCString& soCommand ) { /* works like this: The current process is suspended and a new process is created, child1. The new process forks creating child2, but doesn't suspend. Child2 starts running phredPhrap. child1 creates a button. If the user pushes the button, child2 and all its descendants are killed, and then child1 terminates. If the user does not push the button, when child2 finishes running the phredPhrap script, it kills child1 (its parent) and terminates. In either case, child1 terminates, so the current suspended process can continue. */ int nPid = fork(); if ( nPid < 0 ) { popupErrorMessage( "Problem %d running fork so cannot run miniassembly %s", nPid, soCommand.data() ); return; } else if ( nPid > 0 ) { waitpid( nPid, 0, 0 ); } else { child1ProcessCode( soCommand ); } } static void killProcessAndAllDescendants( RWTValOrderedVector& aPids, RWTValOrderedVector& aPPids, RWTValOrderedVector& aCommands, const int nPidToKill, const RWCString& soCommandOfPidToKill ) { cerr << "killing process " << nPidToKill << "(" << soCommandOfPidToKill << ") and descendants" << endl; for( int nIndex = 0; nIndex < aPids.length(); ++nIndex ) { if ( aPPids[ nIndex ] == nPidToKill ) { // there is a process that is a child of the process to kill // so kill it first killProcessAndAllDescendants( aPids, aPPids, aCommands, aPids[ nIndex ], aCommands[ nIndex ] ); } } if ( kill( nPidToKill, SIGKILL ) != 0 ) { cerr << "error trying to kill process " << nPidToKill << " " << soGetErrno() << endl; } else { cerr << "killed process " << nPidToKill << endl; } } static void cbUserPushedCancel( Widget wid, XtPointer pClientData, XtPointer pCallData ) { union intXtPointerUnion uPidPhredPhrap; uPidPhredPhrap.pXtPointer = pClientData; int nPidPhredPhrap = uPidPhredPhrap.n; FILE* pPS = popen( "ps -al", "r" ); // make a list of pids and parent pids const int nMaxLineSize = 1000; RWCString soLine( (size_t) nMaxLineSize ); if ( fgets( soLine.data(), nMaxLineSize, pPS ) == NULL ) { cerr << "could not read header line of ps so can't terminate phredPhrap" << endl; exit( 1 ); } soLine.nCurrentLength_ = strlen( soLine.data() ); RWCTokenizer tokHeading( soLine ); int nHeading = -1; // set up for first ++ int nPidField = -666; int nPPidField = -666; int nCmdField = -666; RWCString soHeading; while( !( soHeading = tokHeading() ).isNull() ) { ++nHeading; if ( soHeading == "PID" ) { nPidField = nHeading; } else if ( soHeading == "PPID" ) { nPPidField = nHeading; } else if ( soHeading == "CMD" ) { nCmdField = nHeading; } } if ( nPidField == -666 || nPPidField == -666 ) { cerr << "could not find PID or PPID in ps header so can't terminate phredPhrap" << endl; exit( 1 ); } RWTValOrderedVector aPids; RWTValOrderedVector aPPids; RWTValOrderedVector aCommands; while( fgets( soLine.data(), nMaxLineSize, pPS ) != NULL ) { soLine.nCurrentLength_ = strlen( soLine.data() ); RWTValOrderedVector aFields; RWCTokenizer tokPSLine( soLine ); RWCString soField; while( !( soField = tokPSLine() ).isNull() ) { aFields.insert( soField ); } if ( aFields.length() <= MAX( nPidField, nPPidField ) ) { cerr << "problem: couldn't find PID and PPID fields on this line: " << soLine << endl; continue; } int nPid; if ( !bIsNumericMaybeWithWhitespace( aFields[ nPidField ], nPid ) ) { cerr << "error: couldn't understand field " << nPidField << " in line " << soLine << endl; continue; } int nPPid; if ( !bIsNumericMaybeWithWhitespace( aFields[ nPPidField ], nPPid ) ) { cerr << "error: couldn't understand field " << nPPidField << " in line " << soLine << endl; continue; } aPids.insert( nPid ); aPPids.insert( nPPid ); if ( nCmdField != -666 ) { if ( nCmdField < aFields.length() ) { aCommands.insert( aFields[ nCmdField ] ); } else { aCommands.insert( aFields[ aFields.length() - 1 ] ); } } else { aCommands.insert( "couldn't find" ); } } pclose( pPS ); killProcessAndAllDescendants( aPids, aPPids, aCommands, nPidPhredPhrap, "?" ); // soCommand exit( 1 ); } //extern String* aszFallbackResources; static String aszFallbackResources[] = { // "system" font, used on labels, buttons, menus, etc. // "miniassembly*fontList: helvetica", // drawing font used in contigwin "miniassembly*font: -misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1", "miniassembly*fontList: -misc-fixed-bold-r-normal--13-100-100-100-c-70-iso8859-1", "miniassembly*foreground: Black", // colors and shadows // "miniassembly*troughColor: Grey45", "miniassembly*troughColor: Black", "miniassembly*background: Grey77", "miniassembly*topShadowColor: Grey88", "miniassembly*bottomShadowColor: Grey45", "miniassembly*shadowThickness: 2", // these need to be reversed appearance consistent with diboxes, etc. "miniassembly*mainwin.topShadowColor: Grey45", "miniassembly*mainwin.bottomShadowColor: Grey88", // colors in trace window "miniassembly*scaleDrawingArea.background: black", "miniassembly*consensusDrawingArea.background: black", "miniassembly*editableBasesDrawingArea.background: black", "miniassembly*tagsDrawingArea.background: black", "miniassembly*phredCalledBasesDrawingArea.background: black", "miniassembly*ABICalledBasesDrawingArea.background: black", "miniassembly*tracesDrawingArea.background: black", // "miniassembly*assemblyView*assemblyViewDrawingArea.background: white", // time in milliseconds--very long time for recognizing double clicks "miniassembly*doubleClickInterval: 400", // "miniassembly*contigwin.background: Black", // "miniassembly*scaleNumbers.foreground: Yellow", // "miniassembly*scaleGraphics.foreground: Yellow", // scale widgets require messing with for some obscure reason "miniassembly*verticalScale.height: 18", "miniassembly*horizontalScale.height: 18", // not sure this belongs here, but users will probably want // to mess with these ranges and defaults "miniassembly*verticalScale.value: 100", "miniassembly*verticalScale.maximum: 400", "miniassembly*verticalScale.minimum: 1", "miniassembly*horizontalScale.value: 10", "miniassembly*horizontalScale.maximum: 50", "miniassembly*horizontalScale.minimum: 3", // infobuttons are used to display current filename, fragment, etc. // pressing (usually) them supplies more info // "miniassembly*infobutton.fontList: helvetica", // "miniassembly*textfield.fontList: helvetica", "miniassembly*textfield.background: Grey70", // for textbox object "miniassembly*textBox.fontList: -misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1", "miniassembly*navtextfield*fontList: -misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1", "miniassembly*navigator*fontList: -misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1", "miniassembly.title: Miniassembly", "miniassembly*contigwin.background: black", "miniassembly*scaleNumbers.foreground: black", "miniassembly*scaleGraphics.foreground: black", NULL // list is null-terminated }; void miniassembly :: child1ProcessCode( const RWCString& soCommand ) { // first, start up phrap int nPidChild2 = fork(); if ( nPidChild2 == 0 ) { child2ProcessCode( soCommand ); exit( 1 ); // probably will never get here } // let's put up a button Arg aArg[20]; int nArg; XtAppContext ctxAppContext; nArg = 0; Widget widTopLevel = XtAppInitialize( &ctxAppContext, "miniassembly", NULL, 0, &nArg, NULL, // (String*) NULL, aszFallbackResources, NULL, (Cardinal) 0 ); /* Create a push button widget */ Widget widCancelButton = XtVaCreateManagedWidget( " Cancel Miniassembly ", xmPushButtonWidgetClass, widTopLevel, NULL ); XtAddCallback( widCancelButton, XmNactivateCallback, cbUserPushedCancel, (void*) nPidChild2 ); XtRealizeWidget( widTopLevel ); XtAppMainLoop( ctxAppContext ); } void miniassembly :: child2ProcessCode( const RWCString& soCommand ) { int nRetStat = system( (char*) soCommand.data() ); if ( nRetStat != 0 ) { // how will we display this error message? cerr << "error " << nRetStat; if ( strerror( nRetStat ) ) { cerr << " which means " << strerror( nRetStat ); } cerr << " when running phredPhrap. See xterm for details." << endl; } // kill parent (child1) when done int nPid = getppid(); if ( kill( nPid, SIGKILL ) != 0 ) { cerr << "error trying to kill parent process " << nPid << " " << soGetErrno() << endl; } }