/***************************************************************************** # 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 #include #include #include #include #include #include #include "assert.h" #include "consed.h" #include "handleWindowManagerDelete2.h" #include "consedParameters.h" #include "hp_exception_kludge.h" #include "filePopupAndGetAceFilename.h" #include "rwtptrorderedvector.h" #include "filenamePlus.h" #include "rwcregexp.h" #include "popupErrorMessage.h" #include #include #include #include #include "rwcstring.h" #include "filename.h" void cbExitConsed( Widget wid, XtPointer pClientData, XtPointer pCallData ) { exit( 1 ); } static void cbUserClickedOpenButton( Widget wid, XtPointer pClientData, XtPointer pCallData ) { filePopupAndGetAceFilename* pFilePopup = (filePopupAndGetAceFilename*) pClientData; TRY_CATCH_WRAPPER( pFilePopup->userClickedOpenButton() ); } static void cbUserDoubleClicked( Widget wid, XtPointer pClientData, XtPointer pCallData ) { filePopupAndGetAceFilename* pFilePopup = (filePopupAndGetAceFilename*) pClientData; TRY_CATCH_WRAPPER( pFilePopup->userDoubleClicked( wid, pCallData ) ); } void cbUserPushedFilterButton( Widget wid, XtPointer pClientData, XtPointer pCallData ) { filePopupAndGetAceFilename* pFilePopup = (filePopupAndGetAceFilename*) pClientData; TRY_CATCH_WRAPPER( pFilePopup->userPushedFilterButton() ); } filePopupAndGetAceFilename :: ~filePopupAndGetAceFilename() { XtPopdown( widPopupShell_ ); XtDestroyWidget( widPopupShell_ ); } filePopupAndGetAceFilename :: filePopupAndGetAceFilename() : bBlockApplication_( true ) { aListOfAceFiles_.soName_ = "filePopupAndGetAceFilename::aListOfAceFiles_"; widPopupShell_ = XtVaCreatePopupShell( "Ace Files", topLevelShellWidgetClass, GuiApp::pGetGuiApp()->widGetTopLevel(), XmNtitle, "Ace Files", XmNnoResize, False, XmNautoUnmanage, False, XmNtransient, False, XmNdeleteResponse, XmDO_NOTHING, NULL ); handleWindowManagerDelete2( widPopupShell_, cbExitConsed, this ); Widget widForm = XtVaCreateManagedWidget( "form", xmFormWidgetClass, widPopupShell_, XmNshadowThickness, 0, XmNborderWidth, 0, NULL ); const int nSpacingBetweenButtons = 1; const int nNumberOfButtons = 2; int nButtonLocationLeft[6]; int nButtonLocationRight[6]; double dWidthOfAButton = ( 100 - nSpacingBetweenButtons * ( nNumberOfButtons + 1) ) / (double) nNumberOfButtons; for( int nButton = 0; nButton < nNumberOfButtons; ++nButton ) { nButtonLocationLeft[ nButton ] = nSpacingBetweenButtons * ( nButton + 1 ) + (int) (dWidthOfAButton * nButton ); nButtonLocationRight[ nButton ] = nSpacingBetweenButtons * ( nButton + 1 ) + (int) (dWidthOfAButton * ( nButton + 1 )); } widOpenButton_ = XtVaCreateManagedWidget( "Open", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomOffset, 10, XmNtraversalOn, False, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, nButtonLocationLeft[0], XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, nButtonLocationRight[0], NULL ); XtAddCallback(widOpenButton_, XmNactivateCallback, (XtCallbackProc )cbUserClickedOpenButton, this); widExitButton_ = XtVaCreateManagedWidget( "Exit Consed", xmPushButtonWidgetClass, widForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomOffset, 10, XmNtraversalOn, False, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, nButtonLocationLeft[1], XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, nButtonLocationRight[1], NULL ); XtAddCallback(widExitButton_, XmNactivateCallback, (XtCallbackProc )cbExitConsed, this); Widget widFilterLabel = XtVaCreateManagedWidget( "enter pattern (*'s allowed):", xmLabelWidgetClass, widForm, XmNleftAttachment, XmATTACH_FORM, NULL ); Dimension dimSizeOfLabel; XtVaGetValues( widFilterLabel, XmNwidth, &dimSizeOfLabel, NULL ); const int nSpacingBetweenLabel = 5; widEnterFilterPattern_ = XtVaCreateManagedWidget( "aceFileName", xmTextWidgetClass, widForm, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, dimSizeOfLabel + nSpacingBetweenLabel, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, widExitButton_, XmNeditable, True, XmNcursorPositionVisible, True, XmNtraversalOn, True, XmNeditMode, XmSINGLE_LINE_EDIT, NULL ); // typing the "Enter" key in this field has the same // effect as clicking the widFilterButton_ XtAddCallback( widEnterFilterPattern_, XmNactivateCallback, cbUserPushedFilterButton, this ); XtVaSetValues( widFilterLabel, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, widEnterFilterPattern_, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, widEnterFilterPattern_, NULL ); const int nSpacingBeforeFilterButton = 5; Widget widFilterButton = XtVaCreateManagedWidget( "filterButton", xmPushButtonWidgetClass, widForm, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, widEnterFilterPattern_, XmNleftOffset, nSpacingBeforeFilterButton, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, widEnterFilterPattern_, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, widEnterFilterPattern_, NULL ); XtAddCallback( widFilterButton, XmNactivateCallback, cbUserPushedFilterButton, this ); Widget widConnectToBottom = widEnterFilterPattern_; // now work from the top down XmString xmsLabel = XmStringCreateSimple( "Click on an ace file and then click \"Open\"" ); Widget widLabel = XtVaCreateManagedWidget( "Click on an ace file and then click \"Open\"", xmLabelWidgetClass, widForm, XmNtopAttachment, XmATTACH_FORM, XmNtraversalOn, False, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL ); getListOfAceFiles(); if ( aListOfAceFiles_.length() == 0 ) { popupErrorMessage( "There are no ace files in this directory" ); return; } // start out by displaying all ace files aListOfAceFilesToBeDisplayed_ = aListOfAceFiles_; // allocate space for the array of XmStrings XmString* paXms = new XmString[ aListOfAceFilesToBeDisplayed_.length() ]; const int nDateTimeSize = 100; char szDateTime[ nDateTimeSize + 1 ]; // all this funny business is just to hide this from SCCS #define quote( A ) #A for( int nAceFile = 0; nAceFile < aListOfAceFilesToBeDisplayed_.length(); ++nAceFile ) { filenamePlus* pAceFile = aListOfAceFilesToBeDisplayed_[ nAceFile ]; struct tm* pTM = localtime( &( pAceFile->stat_.st_mtime ) ); strftime( szDateTime, nDateTimeSize, quote(%H)":"quote(%M)":"quote(%S)" %e-%h-%Y", pTM ); RWCString soDescription = RWCString( szDateTime ) + " " + (*pAceFile); paXms[ nAceFile ] = XmStringCreateSimple( soDescription.data() ); } int nRows = 30; if ( aListOfAceFilesToBeDisplayed_.length() < nRows ) nRows = aListOfAceFilesToBeDisplayed_.length(); int nArgs; Arg aArg[500]; nArgs = 0; XtSetArg(aArg[nArgs], XmNselectionPolicy, XmSINGLE_SELECT); nArgs++; XtSetArg(aArg[nArgs], XmNitems, paXms); nArgs++; XtSetArg(aArg[nArgs], XmNitemCount, aListOfAceFilesToBeDisplayed_.length()); nArgs++; XtSetArg(aArg[nArgs], XmNtopAttachment, XmATTACH_WIDGET ); nArgs++; XtSetArg(aArg[nArgs], XmNtopWidget, widLabel ); nArgs++; XtSetArg(aArg[nArgs], XmNtopOffset, 0 ); nArgs++; XtSetArg(aArg[nArgs], XmNleftAttachment, XmATTACH_FORM); nArgs++; XtSetArg(aArg[nArgs], XmNrightAttachment, XmATTACH_FORM); nArgs++; XtSetArg(aArg[nArgs], XmNbottomAttachment, XmATTACH_WIDGET); nArgs++; XtSetArg(aArg[nArgs], XmNbottomWidget, widConnectToBottom ); nArgs++; XtSetArg(aArg[nArgs], XmNbottomOffset, 10 ); nArgs++; // XtSetArg(aArg[nArgs], XmNmarginWidth, 0 ); nArgs++; // XtSetArg(aArg[nArgs], XmNmarginHeight, 0 ); nArgs++; XtSetArg(aArg[nArgs], XmNvisibleItemCount, nRows ); nArgs++; // XtSetArg( aArg[nArgs], XmNtextColumns, (short) nWidthInChars ); ++nArgs; widList_ = XmCreateScrolledList( widForm, "navigator", aArg, nArgs); XtManageChild( widList_ ); XtAddCallback( widList_, XmNdefaultActionCallback, (XtCallbackProc )cbUserDoubleClicked, this ); // Widget widText = XmSelectionBoxGetChild( widList_, XmDIALOG_TEXT ); // XtUnmanageChild( widText ); // Widget widTextLabel = XmSelectionBoxGetChild( widList_, XmDIALOG_SELECTION_LABEL ); // XtUnmanageChild( widTextLabel ); XtPopup( widPopupShell_, XtGrabNone ); XmProcessTraversal( widEnterFilterPattern_, XmTRAVERSE_CURRENT ); for(int n = 0; n < aListOfAceFilesToBeDisplayed_.length(); n++) { XmStringFree(paXms[n]); } delete paXms; } void filePopupAndGetAceFilename :: userDoubleClicked( Widget wid, XtPointer pCallData ) { if ( wid != widList_ ) { popupErrorMessage( "please select an ace file and then click open" ); return; } XmListCallbackStruct* pXmListCallbackStruct = (XmListCallbackStruct*) pCallData; // convert from 1-based to 0-based n0SelectedIndex_ = pXmListCallbackStruct->item_position - 1; bBlockApplication_ = false; } void filePopupAndGetAceFilename :: userClickedOpenButton() { // find out which (if any) ace file the user selected by previously // single-clicking int* pPositionList; int nNumberOfSelectedItems; if ( !XmListGetSelectedPos( widList_, &pPositionList, &nNumberOfSelectedItems )) { nNumberOfSelectedItems = 0; popupErrorMessage( "you must select an ace file" ); return; } assert( nNumberOfSelectedItems == 1 ); n0SelectedIndex_ = pPositionList[0] - 1; // convert from 1 based to 0based bBlockApplication_ = false; } FileName filePopupAndGetAceFilename :: filWaitForUserToSelectAceFile() { bBlockApplication_ = true; XEvent xevent; while( bBlockApplication_ ) { XtAppNextEvent( GuiApp::pGetGuiApp()->ctxGetAppContext(), &xevent ); XtDispatchEvent( &xevent ); } FileName filSelectedAceFile = *(aListOfAceFilesToBeDisplayed_[ n0SelectedIndex_ ] ); delete this; return( filSelectedAceFile ); } static int cmpFilesByMtime( const filenamePlus** ppFilenamePlus1, const filenamePlus** ppFilenamePlus2 ) { if ( (*ppFilenamePlus1)->stat_.st_mtime < (*ppFilenamePlus2)->stat_.st_mtime ) return( 1 ); else if ( (*ppFilenamePlus1)->stat_.st_mtime > (*ppFilenamePlus2)->stat_.st_mtime ) return( -1 ); else return( 0 ); } void filePopupAndGetAceFilename :: getListOfAceFiles() { aListOfAceFiles_.clearAndDestroy(); aListOfAceFiles_.resize( 30 ); RWCRegexp regAcePattern( "\\.ace" ); RWCString soWrkFile( ".wrk" ); RWCString soOutFile( ".out" ); RWCString soErrFile( ".err" ); RWCString soAviewFile( ".aview" ); // these 2 are created RWCString soFastaFile( ".fasta" ); // by findSequenceMatchesForConsed.perl RWCString soUnpaddedTransferTable( ".unpadded_transfer_table" ); RWCString soLogFile( ".log" ); DIR *dirFile; struct dirent *pDirEntry; const int nBigNumber = 500; char szCurrentDirectory[ nBigNumber + 1 ]; getcwd( szCurrentDirectory, nBigNumber ); if ( (dirFile = opendir( szCurrentDirectory ) ) == NULL ) { RWCString soError = "could not open directory "; soError += szCurrentDirectory; THROW_ERROR2( soError ); } while( ( pDirEntry = readdir( dirFile ) ) != NULL ) { filenamePlus* pAceFile = new filenamePlus( pDirEntry->d_name ); if ( pAceFile->index( regAcePattern ) == RW_NPOS ) continue; if ( pAceFile->bEndsWith( soWrkFile ) ) continue; if ( pAceFile->bEndsWith( soOutFile ) ) continue; if ( pAceFile->bEndsWith( soErrFile ) ) continue; if ( pAceFile->bEndsWith( soUnpaddedTransferTable ) ) continue; if ( pAceFile->bEndsWith( soAviewFile ) ) continue; if ( pAceFile->bEndsWith( soFastaFile ) ) continue; if ( pAceFile->bEndsWith( soLogFile ) ) continue; // if reached here, the file has .ace but not .wrk in it if ( stat( pAceFile->data(), &pAceFile->stat_ ) ) { RWCString soError = "error trying to get date/time for file "; soError += *pAceFile; soError += " error = "; soError += strerror( errno ); soError += " ("; soError += RWCString( (long) errno ); soError += ")"; popupErrorMessage( soError ); continue; } aListOfAceFiles_.insert( pAceFile ); } // now sort them based on the mtime field (time last modified) void* pArray = aListOfAceFiles_.data(); size_t nNumberOfElements = aListOfAceFiles_.length(); size_t nSizeOfAnElement = sizeof( filenamePlus*); qsort( pArray, nNumberOfElements, nSizeOfAnElement, ( int(*) ( const void*, const void*) ) cmpFilesByMtime ); // check that the sort worked bool bOK = true; for( int nAceFile = 0; nAceFile < aListOfAceFiles_.length() - 1; ++nAceFile ) { filenamePlus* pAceFile1 = aListOfAceFiles_[ nAceFile ]; filenamePlus* pAceFile2 = aListOfAceFiles_[ nAceFile + 1 ]; if ( pAceFile1->stat_.st_mtime < pAceFile2->stat_.st_mtime ) { cerr << "filenamePlus elements out of order " << nAceFile << " and " << nAceFile + 1 << endl; bOK = false; } } if ( !bOK ) { THROW_ERROR( "qsort on aListOfAceFiles_ by stat_.mtime did not work" ); } } void filePopupAndGetAceFilename :: userPushedFilterButton() { char* szValue = XmTextGetString( widEnterFilterPattern_ ); RWCString soUserTypedString( szValue ); XtFree( szValue ); soUserTypedString.stripAllWhitespaceExceptInternal(); // convert * to .* (from globbing pattern to regexp pattern) for( int n = soUserTypedString.length() - 1; n >= 0; --n ) { if ( soUserTypedString[ n ] == '*' ) { soUserTypedString.insert( n, "." ); } } RWCRegexp reg( soUserTypedString ); aListOfAceFilesToBeDisplayed_.clear(); for( int nAceFile = 0; nAceFile < aListOfAceFiles_.length(); ++nAceFile ) { if ( aListOfAceFiles_[ nAceFile ]->bContains( reg ) ) { aListOfAceFilesToBeDisplayed_.insert( aListOfAceFiles_[ nAceFile ] ); } } reDisplayListOfAceFiles(); // put input focus back to the filter box XmProcessTraversal( widEnterFilterPattern_, XmTRAVERSE_CURRENT ); } void filePopupAndGetAceFilename :: reDisplayListOfAceFiles() { // allocate space for the array of XmStrings XmString* paXms = new XmString[ aListOfAceFilesToBeDisplayed_.length() ]; const int nDateTimeSize = 100; char szDateTime[ nDateTimeSize + 1 ]; // all this funny business is just to hide this from SCCS #define quote( A ) #A for( int nAceFile = 0; nAceFile < aListOfAceFilesToBeDisplayed_.length(); ++nAceFile ) { filenamePlus* pAceFile = aListOfAceFilesToBeDisplayed_[ nAceFile ]; struct tm* pTM = localtime( &( pAceFile->stat_.st_mtime ) ); strftime( szDateTime, nDateTimeSize, quote(%H)":"quote(%M)":"quote(%S)" %e-%h-%Y", pTM ); RWCString soDescription = RWCString( szDateTime ) + " " + (*pAceFile); paXms[ nAceFile ] = XmStringCreateSimple( soDescription.data() ); } XtVaSetValues( widList_, XmNitems, paXms, XmNitemCount, aListOfAceFilesToBeDisplayed_.length(), NULL ); }