/***************************************************************************** # 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. # #*****************************************************************************/ // // consed.cpp // // implementation for ConsEd object // #include #include #include "rwcregexp.h" #include #include "consed.h" #include "contigwin.h" #include "tedwin.h" #include "teditor.h" #include "mbt_exception.h" #include "guiapp.h" #include "editaction.h" #include "selection.h" #include "guiQuitTypes.h" #include "guiQuit.h" #include "textbox.h" #include "filePopupAndGetFilename.h" #include "please_wait.h" #include "guiTopWindow.h" #include "gui_search_for_string.h" #include "choose_contig.h" #include "applyEditHistory.h" #include "bEditHistoryFileExists.h" #include "bGuiGetAnswerYesNo.h" #include "deleteFileIfItExists.h" #include "compareContigs.h" #include "consed_version.h" #include "perhapsCreateSocketToControlConsed.h" #include "consedParameters.h" #include #include "popupInfoOrErrorMessageNoFormat.h" #include "restrictionFragmentMobility.h" #include "filePopupAndGetAceFilename.h" // without the below include, despite no compiler or linker error, // the dtor of assemblyView would not be called by delete pAssemblyView_ // and thus the widgets would not be destroyed (but the assemblyView // object would) so exposure events would cause a segmentation fault. #include "assemblyView.h" #include "guiMultiContigNavigator.h" #include "customNavigation.h" #include "popupErrorMessage.h" #include "bIsNumericMaybeWithWhitespace.h" // // static class members // ConsEd* ConsEd::pGlobalConsEd_ = 0; // pointer to sole instance bool ConsEd::bConsEdCreated_ = false; // flag indicates instance exists ConsEd :: ConsEd( ) : pAssembly_(0), bDebug_( false ), bUsingPhdFiles_( true ), pChooseContig_( 0 ), // pGuiMultiContigNavigator_( NULL ), pGuiSearchForString_( NULL ), pAssemblyView_( NULL ) { // // fail crudely if one already exists - we may not have // a gui at all yet // if (bConsEdCreated_) { cerr << "Fatal program error: ConsEd ctor called twice." << endl; cerr.flush(); exit(-1); } // save pointer to yourself pGlobalConsEd_ = this; // remember you have been created (allow no others) bConsEdCreated_ = true; // create the first ContigWin on startup // ContigWin ctor will automatically add itself to ConsEd's array // ContigWin* pNewContigWin = new ContigWin( ); // new up a current selection pSelection_ = new selection(); // load the default directories for the chromatigrams and phd files // These directories are chromat_dir and phd_dir respectively, unless // the environment variables CONSED_CHROMAT_DIR and CONSED_PHD_DIR // are set. char *pChromatDir = getenv( "CONSED_CHROMAT_DIR" ); if ( pChromatDir ) filChromatDir_ = pChromatDir; else filChromatDir_ = "../chromat_dir"; char *pPHDDir = getenv( "CONSED_PHD_DIR" ); if ( pPHDDir ) filPHDDir_ = pPHDDir; else filPHDDir_ = "../phd_dir"; char *pDebug = getenv( "CONSED_DEBUG" ); if (pDebug) bDebug_ = true; } // passed pointer to a derived class of EditAction // tells it to go do itself. void ConsEd :: doEditAction(EditAction* pEditAction, const bool bWriteToEditHistoryFile) { doEditAction2( pEditAction, bWriteToEditHistoryFile, true ); // bRefresh } void ConsEd :: doEditActionNoRefresh( EditAction* pEditAction, const bool bWriteToEditHistoryFile ) { doEditAction2( pEditAction, bWriteToEditHistoryFile, false ); // bRefresh } void ConsEd :: doEditAction2( EditAction* pEdAct, const bool bWriteToEditHistoryFile, const bool bRefresh ) { try { pEdAct->doEdit( bWriteToEditHistoryFile ); } catch (ExceptionBase eb) { // this is one of ours, report it if not done so if (! eb.bUserNotified() ) { GuiApp::popupErrorMessage(eb.szGetDesc()); eb.setUserNotified(); throw eb; // rethrow modified exception } } catch(...) { throw; // re-throw the exception (for now) } // update the edit history list dapEditHistory_.append(pEdAct); if ( bRefresh ) { // send refresh message to all ContigWins. let EditAction // virtual member funs for refreshing ContigWins and Teditors // decide what refreshing/redrawing is really needed for (int nContigWin = 0; nContigWin < dapContigWin_.length(); nContigWin++) { dapContigWin_[nContigWin]->editNotify(pEdAct); } } } // called when the XtApplication timeout says it's // time to blink the cursor. sends cursor draw message // to all ContigWins. void ConsEd :: blinkAllCursors( const bool bBlinkOn) { for (int nContigWin = 0; nContigWin < dapContigWin_.length(); nContigWin++) { dapContigWin_[nContigWin]->drawCursor(true); // checks blink state dapContigWin_[nContigWin]->drawTeditorCursors(true); // ditto } for( int n = 0; n < aCompareContigs_.length(); ++n ) { aCompareContigs_[n]->blinkAllCursors( bBlinkOn ); } if ( pAssemblyView_ ) { pAssemblyView_->drawClickedObjects( bBlinkOn ); } } void ConsEd :: unsetAllCursors() { // important in the case of addNewReads since then the // old cursor position may no longer be valid, such // as if it is at the beginning of a read for (int nContigWin = 0; nContigWin < dapContigWin_.length(); nContigWin++) { dapContigWin_[nContigWin]->clearAllCursors(); } } void ConsEd :: undoLastEditAction( const bool bWriteToEditHistoryFile ) { // pick up a pointer to the last edit action. EditAction* pEdActLast = dapEditHistory_.last(); if ( ! pEdActLast ) { GuiApp :: popupErrorMessage( "Internal program error \nmore undo's than edits in ConsEd::undoLastEditAction \nPlease report to consed author" ); exit( 0 ); } try { pEdActLast->undoEdit( bWriteToEditHistoryFile ); } catch (ExceptionBase eb) { // this is one of ours, report it if not done so if (! eb.bUserNotified() ) { GuiApp::popupErrorMessage(eb.szGetDesc()); eb.setUserNotified(); throw eb; // rethrow modified exception } } catch(...) { throw; // re-throw the exception (for now) } // update the edit history list by removing the last one dapEditHistory_.removeLast(); // send refresh message to all ContigWins. let EditAction // virtual member funs for refreshing ContigWins and Teditors // decide what refreshing/redrawing is really needed for (int nContigWin = 0; nContigWin < dapContigWin_.length(); nContigWin++) { dapContigWin_[nContigWin]->editNotify(pEdActLast); } } // the ContigWin ctor tells the ConsEd that there's a new // one to add to the list or an old one to delete. // (list used for refresh notification, etc.) void ConsEd :: addNewContigWin(ContigWin* pCw) { dapContigWin_.append(pCw); } void ConsEd :: removeContigWin(ContigWin* pCw) { size_t nIndex = dapContigWin_.index(pCw); assert (nIndex != RW_NPOS); dapContigWin_.removeAt(nIndex); } void ConsEd :: deleteAllContigWinsForContig( Contig* pContig ) { for( int nContigWin = dapContigWin_.length() - 1; nContigWin >= 0; --nContigWin ) { ContigWin* pContigWin = dapContigWin_[ nContigWin ]; if ( pContigWin->pContig_ == pContig ) { delete pContigWin; // this will remove it from the list dapContigWin_ } } } void ConsEd :: deleteAllCompareContigWindowsForContig( Contig* pContig ) { for( int n = (int) aCompareContigs_.length() - 1; n >= 0; --n ) { compareContigs* pCompareContigs = aCompareContigs_[ n ]; if ( pCompareContigs->pContig1_ == pContig || pCompareContigs->pContig2_ == pContig ) { delete pCompareContigs; } } } void ConsEd :: deleteAllContigWins() { // note: this should not be called unless you are sure that all compare contig windows // are already down. Otherwise, consed could crash. Instead, use ConsEd::closeAllWindows for( int nContigWin = dapContigWin_.length() - 1; nContigWin >= 0; --nContigWin ) { ContigWin* pContigWin = dapContigWin_[ nContigWin ]; delete pContigWin; } } // // Purpose: Finds the startup contigwin so that a contig can be put // in it // // What it does: This searches through the array of contigwin's and returns // the first one that doesn't have an associated contig. // ContigWin* ConsEd :: pContigWinGetWithNoContig() { ContigWin* pContigWin = NULL; int n = 0; bool bFound = False; while( !bFound && n < dapContigWin_.length() ) { if ( dapContigWin_[n]->pGetContig() == NULL ) { bFound = True; pContigWin = dapContigWin_[n]; } else ++n; } return( pContigWin ); } ContigWin* ConsEd :: pGetFirstContigWin() { return( dapContigWin_[0] ); } void ConsEd :: quitConsed() { if (! pAssemblyGet() ) exit(0); if (! pAssemblyGet()->bChanged() || pCP->bReadOnly_ ) { // just so that people don't accidentally exit out of large // assemblies if ( pGetAssembly()->nGetNumberOfReadsInAssembly() > pCP->nAskAgainIfWantToQuitConsedIfThisManyReads_ ) { if ( !bGuiGetAnswerYesNo( "Are you sure you want to quit? (y/n)" ) ) return; } exit( 0 ); } etypeQuit eWhatQuittingUserWantsToDo; guiQuit* pGuiQuit = new guiQuit(); pGuiQuit->popupAndGetAnswer( eWhatQuittingUserWantsToDo ); delete pGuiQuit; if (eWhatQuittingUserWantsToDo == eCancel ) return; else if (eWhatQuittingUserWantsToDo == eQuitWithoutSaving ) { deleteFileIfItExists( ConsEd::pGetAssembly()->soGetAceFileName() + ".wrk" ); exit(0); } else if (eWhatQuittingUserWantsToDo == eQuitWithoutSavingButSaveEditHistory ) exit(0); else if (eWhatQuittingUserWantsToDo == eSaveBeforeQuitting ) { bool bUserPushedCancel = false; pAssemblyGet()->saveAssembly( bUserPushedCancel, 0 ); if (! bUserPushedCancel ) exit(0); } else assert(false); } void ConsEd :: setAssemblyNameOnAllContigwins( const RWCString& soAssemblyName ) { for (int nContigWin = 0; nContigWin < dapContigWin_.length(); nContigWin++) { dapContigWin_[nContigWin]->setAceFileLabel( soAssemblyName ); } } void ConsEd :: showXResources() { TextBox* pTB = new TextBox( "Fallback X Resources"); RWCString soXResources; GuiApp :: pGetGuiApp()->getFallbackResources( soXResources ); pTB->append( soXResources ); pTB->makeVisible(); } void ConsEd :: showConsedVersion() { TextBox* pTB = new TextBox( "Consed Version"); pTB->append( szConsedVersion ); pTB->makeVisible(); } void ConsEd :: askUserForFileToOpen() { FileName soAceFileToOpen; filePopupAndGetAceFilename* pFilePopupAndGetAceFilename = new filePopupAndGetAceFilename(); soAceFileToOpen = pFilePopupAndGetAceFilename->filWaitForUserToSelectAceFile(); PleaseWait* pPleaseWait = new PleaseWait( GuiApp::pGetGuiApp()->widGetTopLevel() ); // openAssemblyFile has its own try/catch openAssemblyFile(soAceFileToOpen); try { pGetGuiTopWindow()->setAssemblyName( soAceFileToOpen.soGetBasename() ); if ( ! consedParameters::pGetConsedParameters()->bErrorMessageDisplayedAtStartup_ ) XRaiseWindow( XtDisplay( GuiApp::pGetGuiApp()->widGetTopLevel() ), XtWindow( GuiApp::pGetGuiApp()->widGetTopLevel() ) ); delete pPleaseWait; setAssemblyNameOnAllContigwins( soAceFileToOpen.soGetBasename() ); perhapsApplyEditHistoryFile( soAceFileToOpen ); perhapsCreateSocketToControlConsed(); // if open failed, won't get this far updateContigListOnMainConsedWindow(); } catch(ExceptionBase eb) { // this is one of ours, report it if not done so if (! eb.bUserNotified() ) { GuiApp::popupErrorMessage(eb.szGetDesc()); } } } void ConsEd :: openAssemblyFile(const char* szFilePath) { // delete pAssembly_; // toasted, whatever you were try { new Assembly(szFilePath, true ); // bSetGlobalAssembly } catch (ExceptionBase eb) { eb.addStringToDesc( "ace file = " ); eb.addStringToDesc( szFilePath ); // failed for whatever reason // consedParameters::pGetConsedParameters()->bOKToUseGui_ = false; popupInfoOrErrorMessageNoFormat( NULL, // shell of parent true, // error message not into eb.szGetDesc(), false ); // assembly object is not valid exit(1); } if ( pCP->bTerminateAfterStartup_ ) { exit( EXIT_SUCCESS ); } } void ConsEd :: searchForString() { if ( pCP->bAllowMultipleSearchForStringWindows_ ) { pGuiSearchForString_ = new GuiSearchForString(); pGuiSearchForString_->popupAskForSearchString(); } else { if ( pGuiSearchForString_ ) { pGuiSearchForString_->raiseWindow(); } else { pGuiSearchForString_ = new GuiSearchForString(); pGuiSearchForString_->popupAskForSearchString(); } } } void ConsEd :: updateContigListOnMainConsedWindow() { // is there a current assembly? if (! pAssemblyGet() ) { return; } if ( pChooseContig_ ) delete pChooseContig_; pChooseContig_ = new ChooseContig( pAssemblyGet(), "" ); // pattern--show all reads pChooseContig_->fillThyself( true ); // limit # of reads pGetGuiTopWindow()->showListOfContigs( pChooseContig_ ); } void ConsEd :: choseContig( const int nIndex, const bool bReadListNotContigList ) { Contig *pContig; LocatedFragment* pLocatedFragment; pChooseContig_->getChosenContig( nIndex, bReadListNotContigList, pContig, pLocatedFragment ); int nStartPaddedConsPos; if (bReadListNotContigList) { choseContig2( pLocatedFragment ); } else { nStartPaddedConsPos =pContig->nGetFirstDisplayableContigPos(); ContigWin* pContigWin = pPutContigInAContigWin( pContig, nStartPaddedConsPos ); } } void ConsEd :: choseContig2( LocatedFragment* pLocFrag ) { int nStartPaddedConsPos; if (pLocFrag->bComp() ) nStartPaddedConsPos = pLocFrag->nGetHighQualityEndUnlessAllBad(); else nStartPaddedConsPos = pLocFrag->nGetHighQualityStartUnlessAllBad(); ContigWin* pContigWin = pScrollExistingContigWinOrMakeNewContigWin( pLocFrag->pContig_, nStartPaddedConsPos ); pContigWin->moveCursorToFragPos( nStartPaddedConsPos, pLocFrag ); // raise the window pContigWin->raiseWindow(); } // This routine does not use a contigwin that already has this contig // in it. It forces up a new copy of the contig. ContigWin* ConsEd :: pPutContigInAContigWin( Contig* pContig, const int nStartPaddedConsPos ) { // We need a ContigWin to put it in. ContigWin* pContigWin = new ContigWin(); pContigWin->setContig( pContig ); pContigWin->initializeContigWinForNewContig( nStartPaddedConsPos, true ); // put in center return( pContigWin ); } ContigWin* ConsEd :: pGetContigWinByContig( Contig* pContig ) { int nContigWin = 0; bool bFound = false; while( !bFound && nContigWin < dapContigWin_.length() ) { if (pContig == dapContigWin_[ nContigWin ]->pGetContig() ) bFound = true; else nContigWin++; } if (bFound ) return( dapContigWin_[ nContigWin ] ); else return( NULL ); } ContigWin* ConsEd :: pGetSecondContigWinByContig( Contig* pContig ) { bool bFound = false; int nContigWin; for( nContigWin = 0; nContigWin < dapContigWin_.length(); ++nContigWin ) { if ( pContig == dapContigWin_[ nContigWin ]->pGetContig() ) { bFound = true; break; } } if ( !bFound ) return( NULL ); ++nContigWin; // advance over the found one bFound = false; for( ; nContigWin < dapContigWin_.length(); ++nContigWin ) { if ( pContig == dapContigWin_[ nContigWin ]->pGetContig() ) { bFound = true; break; } } if ( bFound ) { return( dapContigWin_[ nContigWin ] ); } else return( NULL ); } ContigWin* ConsEd :: pScrollExistingContigWinOrMakeNewContigWin( Contig* pContig, const int nStartPaddedConsPos ) { // first try to find this contig in an existing contigwin ContigWin* pContigWin = pGetContigWinByContig( pContig ); if (pContigWin ) { pContigWin->scrollToConsensusPosInCenter( nStartPaddedConsPos ); return( pContigWin ); } else { // check that this pContig exists--we must do this by // checking the *pointers*--not the values. index uses // values. So use indexPointers instead. This fixes a bug // in which the old memory still had the contig name in it, // which is what Contig::operator== uses to check if two // contigs are equal which is used by index. if ( pGetAssembly()->dapContigs_.indexByPointers( pContig ) == RW_NPOS ) { THROW_ERROR2( "This contig has changed too much." ); } return( pPutContigInAContigWin( pContig, nStartPaddedConsPos ) ); } } ContigWin* ConsEd :: pScrollExistingContigWinOrMakeNewContigWinAndSetCursorOnConsensus( Contig* pContig, const int nConsPos ) { // first try to find this contig in an existing contigwin ContigWin* pContigWin = pGetContigWinByContig( pContig ); if ( pContigWin ) { pContigWin->scrollToConsensusPosInCenterAndSetCursorOnConsensus( nConsPos ); } else { // check that this Contig exists--we must do this by checking the // *pointers*--not the values. index uses values. So use // indexPointers instead. This fixes a bug in which the old // memory still had the contig name in it, // which is what Contig::operator== uses to check if two // contigs are equal which is used by index. if ( pGetAssembly()->dapContigs_.indexByPointers( pContig ) == RW_NPOS ) { THROW_ERROR2( "This contig has changed too much." ); } pContigWin = pPutContigInAContigWin( pContig, nConsPos ); // not sure if this is necessary...yes, it is. pPutcontigInAContigWin // does do a lot of what happens below, but it does not sort the // reads at the cursor (if the user has that option set), nor does // it set the cursor pContigWin->scrollToConsensusPosInCenterAndSetCursorOnConsensus( nConsPos ); } return pContigWin; } void ConsEd :: perhapsApplyEditHistoryFile( const RWCString& soAceFileOpened ) { // if the edit history is applied when the user started consed -read_only, // the EditAction's will throw and exception which will not be caught // and Consed will crash if ( pCP->bReadOnly_ ) return; bool bEditHistoryFileExistss = bEditHistoryFileExists( soAceFileOpened ); bool bApplyEdits; if (bEditHistoryFileExistss ) { RWCString soQuestion( "There is an edit history file (a .wrk file).\nConsed may have crashed during a previous \nsession using this same ace file:\n"); soQuestion += soAceFileOpened; soQuestion += "\nDo you want to apply those edits?\n(If you do not apply the edits, you may lose them.)"; bApplyEdits = bGuiGetAnswerYesNo( soQuestion ); } else bApplyEdits = false; if (bApplyEdits) { PleaseWait* pPleaseWait = new PleaseWait( GuiApp::pGetGuiApp()->widGetTopLevel() ); applyEditHistory( soAceFileOpened ); delete pPleaseWait; pAssemblyGet()->setOpenEditHistoryForAppendFlag(); } else pAssemblyGet()->clearOpenEditHistoryForAppendFlag(); } void ConsEd :: createCompareContigs( ContigWin* pContigWin, int nConsensusPosition ) { aCompareContigs_.insert( new compareContigs( pContigWin, nConsensusPosition ) ); } compareContigs* ConsEd :: pCreateCompareContigsForAssemblyView() { compareContigs* pCC = new compareContigs(); aCompareContigs_.insert( pCC ); return( pCC ); } void ConsEd :: ccompareContigs(ContigWin* pContigWin) { if (!pContigWin->pGetEditCursor()->bCursorValid() ) { GuiApp::popupErrorMessage( "You must first click on a read to set the cursor" ); return; } compareContigs* pCompareContigs; bool bFirstNotSecondContigInCompareContigsWindow; findCompareContigWindow( pCompareContigs, bFirstNotSecondContigInCompareContigsWindow ); int nConsensusPosition = pContigWin->pGetEditCursor()->nConsPosGet(); if ( bFirstNotSecondContigInCompareContigsWindow ) { createCompareContigs( pContigWin, nConsensusPosition ); } else { pCompareContigs->addSecondContig( pContigWin, nConsensusPosition ); } } char* ConsEd :: szGetConsedVersion() { return( szConsedVersion ); } void ConsEd :: refreshAllContigWinsAndAllTeditors() { // send refresh message to all ContigWins. for (int nContigWin = 0; nContigWin < dapContigWin_.length(); nContigWin++) { dapContigWin_[nContigWin]->refreshContigWinAndTeditor(); } } void ConsEd :: refreshAllContigWins() { // send refresh message to all ContigWins. for (int nContigWin = 0; nContigWin < dapContigWin_.length(); nContigWin++) { dapContigWin_[nContigWin]->drawBasesAndConsensus( true ); // erase first } } // just for switching between ways of ordering reads void ConsEd :: getNewContigViewsForAllContigWins() { for (int nContigWin = 0; nContigWin < dapContigWin_.length(); nContigWin++) { dapContigWin_[nContigWin]->getNewContigView(); } } EditAction* ConsEd :: pGetLastEditAction() { EditAction* pEditAction; if ( dapEditHistory_.isEmpty() ) pEditAction = NULL; else pEditAction = dapEditHistory_.last(); return( pEditAction ); } void ConsEd :: disallowUndos() { dapEditHistory_.clearAndDestroy(); for( int nContigWin = 0; nContigWin < dapContigWin_.length(); ++nContigWin ) { ContigWin* pContigWin = dapContigWin_[ nContigWin ]; Teditor* pTeditor = pContigWin->pGetTeditor(); if ( pTeditor ) { for( int nTedWin = 0; nTedWin < pTeditor->nNumberOfTedWins(); ++nTedWin ) { TedWin* pTedWin = pTeditor->pGetTedWin( nTedWin ); GuiTedWin* pGuiTedWin = pTedWin->pGetGuiTedWin(); pGuiTedWin->deactivateUndoButton(); } } } } void ConsEd :: findCompareContigWindow( compareContigs*& pCompareContigs, bool& bFirstNotSecondContigInCompareContigsWindow ) { for( int n = 0; n < aCompareContigs_.length(); ++n ) { compareContigs* pCompareContigsTemp = aCompareContigs_[n]; // case in which the compare contigs window is currently in use // by 2 contigs if ( pCompareContigsTemp->pContig2_ && pCompareContigsTemp->pContig1_ ) continue; // case in which a join has been made using this compare contigs window if ( !pCompareContigsTemp->pContig2_ && !pCompareContigsTemp->pContig1_ ) continue; bFirstNotSecondContigInCompareContigsWindow = false; pCompareContigs = pCompareContigsTemp; return; } // if reached here, then all the compareContigs windows were full bFirstNotSecondContigInCompareContigsWindow = true; } bool ConsEd :: bFoundAndDeletedThisCompareContigsFromList( compareContigs* pCompareContigs ) { for( int n = 0; n < aCompareContigs_.length(); ++n ) { compareContigs* pCompareContigsTemp = aCompareContigs_[n]; if ( pCompareContigsTemp == pCompareContigs ) { aCompareContigs_.removeAt( n ); return( true ); } } // if reached here, couldn't find the compareContigs in the list return( false ); } bool ConsEd :: bIsThisContigWinOnAnyCompareContigsWindow( ContigWin* pContigWin ) { for( int n = 0; n < aCompareContigs_.length(); ++n ) { compareContigs* pCompareContigs = aCompareContigs_[n]; if ( pCompareContigs->pContigWin1_ == pContigWin || pCompareContigs->pContigWin2_ == pContigWin ) return( true ); } return( false ); } void ConsEd :: deleteOtherCompareContigsWindowsWithSameContigs( compareContigs* pCompareContigsForJoin, Contig* pContig1, Contig* pContig2 ) { for( int n = aCompareContigs_.length() - 1; n >= 0; --n ) { compareContigs* pCompareContigs = aCompareContigs_[ n ]; bool bFoundContig = false; if ( pCompareContigs->pContigWin1_ ) { if ( ( pCompareContigs->pContigWin1_->pContig_ == pContig1 ) || ( pCompareContigs->pContigWin1_->pContig_ == pContig2 ) ) bFoundContig = true; } if ( pCompareContigs->pContigWin2_ ) { if ( ( pCompareContigs->pContigWin2_->pContig_ == pContig1 ) || ( pCompareContigs->pContigWin2_->pContig_ == pContig2 ) ) bFoundContig = true; } if ( bFoundContig ) { // this compare contigs window has one of the contigs that will // be joined together. Thus we want to delete the contig and hence // the compare contigs window if ( pCompareContigsForJoin != pCompareContigs ) delete pCompareContigs; } } } void ConsEd :: deleteAllCompareContigWindows() { for( int n = 0; n < aCompareContigs_.length(); ++n ) { compareContigs* pCompareContigs = aCompareContigs_[ n ]; delete pCompareContigs; } } float ConsEd :: fGetPositionOnGelFromRestrictionFragmentSize( const int nFragSize ) { int nMaxIndex = sizeof( nRestrictionFragmentSize ) / sizeof( int ) - 1; // boundary cases: // 1) below lowest value // 2) above highest value if ( nFragSize < nRestrictionFragmentSize[0] ) { return( fInterpolateGelPosition( nFragSize, nRestrictionFragmentSize[0], fPositionOnGel[0], nRestrictionFragmentSize[1], fPositionOnGel[1] ) ); } if ( nFragSize > nRestrictionFragmentSize[ nMaxIndex ] ) { return( fInterpolateGelPosition( nFragSize, nRestrictionFragmentSize[ nMaxIndex - 1 ], fPositionOnGel[ nMaxIndex - 1 ], nRestrictionFragmentSize[ nMaxIndex ], fPositionOnGel[ nMaxIndex ] ) ); } int nLowerIndex; int nUpperIndex; getRangeOfFragmentIndicesForFragmentSize( nFragSize, nLowerIndex, nUpperIndex ); if ( nLowerIndex == nUpperIndex ) { return( fPositionOnGel[ nLowerIndex ] ); } // normal case in which nFragSize is within the range--must interpolate return( fInterpolateGelPosition( nFragSize, nRestrictionFragmentSize[ nLowerIndex ], fPositionOnGel[ nLowerIndex ], nRestrictionFragmentSize[ nUpperIndex ], fPositionOnGel[ nUpperIndex ] ) ); } float ConsEd :: fInterpolateGelPosition( const int nFragSize, const int nLowerFragSize, const float fLowerGelPosition, const int nUpperFragSize, const float fUpperGelPosition ) { float fLogLowerFragSize = log10( (double) nLowerFragSize ); float fLogUpperFragSize = log10( (double) nUpperFragSize ); float fA = ( fLowerGelPosition - fUpperGelPosition ) / ( 1.0/fLogLowerFragSize - 1.0 / fLogUpperFragSize ); float fB = ( fLowerGelPosition * fLogLowerFragSize - fUpperGelPosition * fLogUpperFragSize ) / ( fLogLowerFragSize - fLogUpperFragSize ); return( fA / log10( (double) nFragSize ) + fB ); } void ConsEd :: getRangeOfFragmentIndicesForFragmentSize( const int nFragSize, int& nLowerIndex, int& nUpperIndex ) { int nMaxIndex = sizeof( nRestrictionFragmentSize ) / sizeof( int ) - 1; int nRangeStart = 0; int nRangeEnd = nMaxIndex; assert( nRestrictionFragmentSize[nRangeStart] <= nFragSize ); assert( nFragSize <= nRestrictionFragmentSize[ nRangeEnd ] ); // this will *always* return an interval that is size 1, even // if nFragSize matches one or the other of the ends of the interval while( true ) { int nRangeLen = nRangeEnd - nRangeStart; if ( nRangeLen == 1 ) { nLowerIndex = nRangeStart; nUpperIndex = nRangeEnd; return; } int nTestIndex = ( nRangeLen / 2 ) + nRangeStart; if ( nFragSize < nRestrictionFragmentSize[ nTestIndex ] ) { // . . . . + . . (+ is nTestIndex) // * (pTMatch) // So overshot. nRangeEnd = nTestIndex; } else { // . . + . . . . // * (pTMatch) nRangeStart = nTestIndex; } // if ( nRestrictionFragmentSize[ nTestIndex ] == nFragSize ) { else } // while( true ); } bool ConsEd :: bCouldGetFragmentSizeFromGelPosition( const float fGelPosition, int& nFragSize ) { int nMinFragSize = 1; // first, find a max frag size const int nTooBig = 100000000; // E8 int nTryMaxFragSize = 3000; while( fGelPosition < fGetPositionOnGelFromRestrictionFragmentSize( nTryMaxFragSize ) && nTryMaxFragSize < nTooBig ) { nTryMaxFragSize *= 2; } int nMaxFragSize = nTryMaxFragSize; if ( nTryMaxFragSize >= nTooBig ) { return( false ); } while( ( nMinFragSize + 2 ) <= nMaxFragSize ) { int nMiddle = ( nMinFragSize + nMaxFragSize ) / 2; if ( fGelPosition >= fGetPositionOnGelFromRestrictionFragmentSize( nMiddle ) ) { nMaxFragSize = nMiddle; } else nMinFragSize = nMiddle; } assert( fGetPositionOnGelFromRestrictionFragmentSize( nMaxFragSize ) <= fGelPosition && fGelPosition <= fGetPositionOnGelFromRestrictionFragmentSize( nMinFragSize ) ); nFragSize = nMinFragSize; return( true ); } void ConsEd :: whatToDoBeforeModifyAssembly() { if ( pAssemblyView_ ) { delete pAssemblyView_; pAssemblyView_ = NULL; } pCP->bNeedToSetContigTemplateArrays_ = true; } void ConsEd :: closeAllWindows() { deleteAllCompareContigWindows(); deleteAllContigWins(); if ( pAssemblyView_ ) { delete pAssemblyView_; pAssemblyView_ = NULL; } for( int nGui = aGuiMultiContigNavigator_.length() - 1; nGui >= 0; --nGui ) { delete aGuiMultiContigNavigator_[ nGui ]; // the destructor removes itself from aGuiMultiContigNavigator_ } if ( pGuiSearchForString_ ) { delete pGuiSearchForString_; pGuiSearchForString_ = NULL; } } void ConsEd :: addGuiMultiContigNavigator( guiMultiContigNavigator* pGuiMultiContigNav ) { aGuiMultiContigNavigator_.insert( pGuiMultiContigNav ); } void ConsEd :: startUpConsedWithCustomNavigationFile( const FileName& filCustomNavigationFile ) { gotoList* pGotoList = new gotoList(); RWCString soTitle; try { readCustomNavigationFile( filCustomNavigationFile, soTitle, pGotoList ); } catch( ExceptionBase eb ) { if ( !eb.bUserNotified() ) { popupErrorMessage( eb.szGetDesc() ); } sleep( 3 ); exit( 1 ); } guiMultiContigNavigator* pGui = new guiMultiContigNavigator( soTitle, // title soTitle, // first line "", // second line 75, // width in chars soEmptyString, // title of special purpose button NULL, // callback for special purpose button NULL, // client data for special purpose button NULL, // widTopLevelShellToBeConnectedTo, NULL means top level window pGotoList ); ConsEd::pGetConsEd()->addGuiMultiContigNavigator( pGui ); } void ConsEd :: startUpConsedAtMainContigPos( const RWCString& soUnpaddedPos ) { int nUnpaddedPos; if ( !bIsNumericMaybeWithWhitespace( soUnpaddedPos, nUnpaddedPos ) ) { cerr << "fatal: " << soUnpaddedPos << " is not numeric" << endl; exit( 1 ); } // find the contig with most reads Assembly* pAssembly = ConsEd::pGetAssembly(); Contig* pContigWithMostReads = 0; int nNumberOfReads = -666; for( int nContig = 0; nContig < pAssembly->nNumContigs(); ++nContig ) { Contig* pContig = pAssembly->pGetContig( nContig ); if ( pContig->nGetNumberOfFragsInContig() > nNumberOfReads ) { nNumberOfReads = pContig->nGetNumberOfFragsInContig(); pContigWithMostReads = pContig; } } if ( !pContigWithMostReads ) { cerr << "fatal: couldn't find contig with most reads" << endl; exit( 1 ); } int nConsPos = pContigWithMostReads->nPaddedIndex( nUnpaddedPos ); ContigWin* pContigWin = ConsEd::pGetConsEd()->pScrollExistingContigWinOrMakeNewContigWin( pContigWithMostReads, nConsPos ); pContigWin->moveCursorToConsPos( nConsPos ); // raise the window pContigWin->raiseWindow(); }