0fc118ce918050c1e46d4e94572923b2bc924a31 tdreszer Tue Apr 5 21:35:42 2011 -0700 Cleaned out some ifdefs and made track search name and description fields work like file search diff --git src/hg/hgFileSearch/hgFileSearch.c src/hg/hgFileSearch/hgFileSearch.c index ab5523b..1f6ef5e 100644 --- src/hg/hgFileSearch/hgFileSearch.c +++ src/hg/hgFileSearch/hgFileSearch.c @@ -22,162 +22,113 @@ #define FILE_SEARCH_WHAT "Downloadable ENCODE Files" #define FILE_SEARCH_NAME FILE_SEARCH_WHAT " Search" #define FILE_SEARCH "hgfs_Search" #define FILE_SEARCH_FORM "fileSearch" #define FILE_SEARCH_CURRENT_TAB "fsCurTab" #define FILE_SEARCH_ON_FILETYPE "fsFileType" // These are common with trackSearch. Should they be? #define TRACK_SEARCH_SIMPLE "tsSimple" #define TRACK_SEARCH_ON_NAME "tsName" #define TRACK_SEARCH_ON_GROUP "tsGroup" #define TRACK_SEARCH_ON_DESCR "tsDescr" #define TRACK_SEARCH_SORT "tsSort" -#define SUPPORT_COMPOSITE_SEARCH -#ifdef SUPPORT_COMPOSITE_SEARCH //#define USE_TABS -#endif///def SUPPORT_COMPOSITE_SEARCH -#ifdef SUPPORT_COMPOSITE_SEARCH -// make a matchString function to support "contains", "is" etc. and wildcards in contains - -// ((sameString(op, "is") && !strcasecmp(track->shortLabel, str)) || - -#define MATCH_ON_EACH_WORD -#ifdef MATCH_ON_EACH_WORD -#define MATCH_ON_WILDS static boolean matchToken(char *string, char *token) { +// do this with regex ? Would require all sorts of careful parsing for ()., etc. if (string == NULL) return (token == NULL); if (token == NULL) return TRUE; if (!strchr(token,'*') && !strchr(token,'?')) return (strcasestr(string,token) != NULL); -#ifdef MATCH_ON_WILDS char wordWild[1024]; safef(wordWild,sizeof wordWild,"*%s*",token); return wildMatch(wordWild, string); -// do this with regex ? Would require all sorts of careful parsing for ()., etc. -//safef(wordWild,sizeof wordWild,"^*%s*$",token); -//regex_t regEx; -//int err = regcomp(®Ex, token, REG_NOSUB | REG_ICASE); -//if(err != 0) // Compile the regular expression so that it can be used. Use: REG_EXTENDED ? -// { -// char buffer[128]; -// regerror(err, ®Ex, buffer, sizeof buffer); -// warn("ERROR: Invalid regular expression: [%s] %s\n",token,buffer); -// regfree(®Ex); -// return FALSE; -// } -//err = regexec(®Ex, mdbVar->val, 0, NULL, 0); -//regfree(®Ex); -//return (err == 0); - -#endif//def MATCH_ON_WILDS } static boolean doesNameMatch(struct trackDb *tdb, struct slName *wordList) // We parse str and look for every word at the start of any word in track description (i.e. google style). { -if (tdb->html == NULL) +if (tdb->shortLabel == NULL || tdb->longLabel == NULL) return (wordList != NULL); struct slName *word = wordList; for(; word != NULL; word = word->next) { if (!matchToken(tdb->shortLabel,word->name) && !matchToken(tdb->longLabel, word->name)) return FALSE; } return TRUE; } static boolean doesDescriptionMatch(struct trackDb *tdb, struct slName *wordList) // We parse str and look for every word at the start of any word in track description (i.e. google style). { -//static boolean tryitOneCycle=TRUE; if (tdb->html == NULL) return (wordList != NULL); if (strchr(tdb->html,'\n')) strSwapChar(tdb->html,'\n',' '); // DANGER: don't own memory. However, this CGI will use html for no other purpose struct slName *word = wordList; for(; word != NULL; word = word->next) { if (!matchToken(tdb->html,word->name)) return FALSE; } return TRUE; } -#endif///def MATCH_ON_EACH_WORD static struct trackDb *tdbFilterBy(struct trackDb **pTdbList, char *name, char *description, char *group) // returns tdbs that match supplied criterion, leaving unmatched in list passed in { -#ifdef MATCH_ON_EACH_WORD // Set the word lists up once struct slName *nameList = NULL; if (name) nameList = slNameListOfUniqueWords(cloneString(name),TRUE); // TRUE means respect quotes struct slName *descList = NULL; if (description) descList = slNameListOfUniqueWords(cloneString(description),TRUE); -#endif///def MATCH_ON_EACH_WORD struct trackDb *tdbList = *pTdbList; struct trackDb *tdbRejects = NULL; struct trackDb *tdbMatched = NULL; -#ifndef MATCH_ON_EACH_WORD -char nameWild[256]; -if (name) - safef(nameWild,sizeof nameWild,"*%s*",name); -char descWild[512]; -if (description) - safef(descWild,sizeof descWild,"*%s*",description); -#endif///ndef MATCH_ON_EACH_WORD while (tdbList != NULL) { struct trackDb *tdb = slPopHead(&tdbList); if (!tdbIsComposite(tdb)) slAddHead(&tdbRejects,tdb); else if (group && differentString(tdb->grp,group)) slAddHead(&tdbRejects,tdb); -#ifdef MATCH_ON_EACH_WORD else if (name && !doesNameMatch(tdb, nameList)) slAddHead(&tdbRejects,tdb); else if (description && !doesDescriptionMatch(tdb, descList)) slAddHead(&tdbRejects,tdb); -#else///ifndef MATCH_ON_EACH_WORD - else if (name && (!wildMatch(nameWild,tdb->shortLabel) && !wildMatch(nameWild,tdb->longLabel))) - slAddHead(&tdbRejects,tdb); - else if (description && (tdb->html == NULL || !wildMatch(descWild,tdb->html))) - slAddHead(&tdbRejects,tdb); -#endif///ndef MATCH_ON_EACH_WORD else slAddHead(&tdbMatched,tdb); } -//slReverse(&tdbRejects); // Needed? -//slReverse(&tdbMatched); // Needed? *pTdbList = tdbRejects; //warn("matched %d tracks",slCount(tdbMatched)); return tdbMatched; } static boolean mdbSelectsAddFoundComposites(struct slPair **pMdbSelects,struct trackDb *tdbsFound) // Adds a composite mdbSelect (if found in tdbsFound) to the head of the pairs list. // If tdbsFound is NULL, then add dummy composite search criteria { // create comma separated list of composites struct dyString *dyComposites = dyStringNew(256); struct trackDb *tdb = tdbsFound; for(;tdb != NULL; tdb = tdb->next) { @@ -190,54 +141,53 @@ } } if (dyStringLen(dyComposites) > 0) { char *composites = dyStringCannibalize(&dyComposites); composites[strlen(composites) - 1] = '\0'; // drop the last ',' //warn("Found composites: %s",composites); slPairAdd(pMdbSelects,MDB_VAR_COMPOSITE,composites); // Composite should not already be in the list, because it is only indirectly sortable return TRUE; } //warn("No composites found"); dyStringFree(&dyComposites); return FALSE; } -#endif///def SUPPORT_COMPOSITE_SEARCH #ifdef USE_TABS static struct slRef *simpleSearchForTdbs(struct trix *trix,char **descWords,int descWordCount) // Performs the simple search and returns the found tracks. { struct slRef *foundTdbs = NULL; struct trixSearchResult *tsList; for(tsList = trixSearch(trix, descWordCount, descWords, TRUE); tsList != NULL; tsList = tsList->next) { struct trackDb *tdb = (struct track *) hashFindVal(trackHash, tsList->itemId); if (track != NULL) // It is expected that this is NULL (e.g. when the trix references trackDb tracks which have no tables) { refAdd(&foundTdbs, tdb); } } return foundTdbs; } #endif///def USE_TABS struct slName *tdbListGetGroups(struct trackDb *tdbList) // Returns a list of groups found in the tdbList -// FIXME: Should be movedf to trackDbCustom and shared +// FIXME: Should be moved to trackDbCustom and shared { struct slName *groupList = NULL; char *lastGroup = "[]"; struct trackDb *tdb = tdbList; for(;tdb!=NULL;tdb=tdb->next) { if (differentString(lastGroup,tdb->grp)) lastGroup = slNameStore(&groupList, tdb->grp); } return groupList; } struct grp *groupsFilterForTdbList(struct grp **grps,struct trackDb *tdbList) { struct grp *grpList = *grps; @@ -260,123 +210,105 @@ static void doFileSearch(char *db,char *organism,struct cart *cart,struct trackDb *tdbList) { if (!advancedJavascriptFeaturesEnabled(cart)) { warn("Requires advanced javascript features."); return; } struct sqlConnection *conn = hAllocConn(db); boolean metaDbExists = sqlTableExists(conn, "metaDb"); if (!sqlTableExists(conn, "metaDb")) { warn("Assembly %s %s does not support Downloadable Files search.", organism, hFreezeFromDb(db)); hFreeConn(&conn); return; } -#ifdef SUPPORT_COMPOSITE_SEARCH char *nameSearch = cartOptionalString(cart, TRACK_SEARCH_ON_NAME); char *descSearch=NULL; -#endif///def SUPPORT_COMPOSITE_SEARCH char *fileTypeSearch = cartOptionalString(cart, FILE_SEARCH_ON_FILETYPE); boolean doSearch = sameWord(cartUsualString(cart, FILE_SEARCH,"no"), "search"); #ifdef ONE_FUNC struct hash *parents = newHash(4); #endif///def ONE_FUNC boolean searchTermsExist = FALSE; // FIXME: Why is this needed? int cols; -#ifdef SUPPORT_COMPOSITE_SEARCH #ifdef USE_TABS enum searchTab selectedTab = simpleTab; char *currentTab = cartUsualString(cart, FILE_SEARCH_CURRENT_TAB, "simpleTab"); if(sameString(currentTab, "simpleTab")) { selectedTab = simpleTab; descSearch = cartOptionalString(cart, TRACK_SEARCH_SIMPLE); freez(&nameSearch); } else if(sameString(currentTab, "filesTab")) { selectedTab = filesTab; descSearch = cartOptionalString(cart, TRACK_SEARCH_ON_DESCR); } #else///ifndef USE_TABS enum searchTab selectedTab = filesTab; descSearch = cartOptionalString(cart, TRACK_SEARCH_ON_DESCR); #endif///ndef USE_TABS -#ifndef MATCH_ON_EACH_WORD -if(descSearch) - stripChar(descSearch, '"'); -#endif///ndef MATCH_ON_EACH_WORD - #ifdef USE_TABS struct trix *trix; char trixFile[HDB_MAX_PATH_STRING]; getSearchTrixFile(db, trixFile, sizeof(trixFile)); trix = trixOpen(trixFile); #endif///def USE_TABS -#endif///def SUPPORT_COMPOSITE_SEARCH printf("<div style='max-width:1080px;'>"); // FIXME: Do we need a form at all? -//printf("<form action='%s' name='%s' id='%s' method='get'>\n\n", hgTracksName(),FILE_SEARCH_FORM,FILE_SEARCH_FORM); printf("<form action='../cgi-bin/hgFileSearch' name='%s' id='%s' method='get'>\n\n", FILE_SEARCH_FORM,FILE_SEARCH_FORM); cartSaveSession(cart); // Creates hidden var of hgsid to avoid bad voodoo -//safef(buf, sizeof(buf), "%lu", clock1()); -//cgiMakeHiddenVar("hgt_", buf); // timestamps page to avoid browser cache printf("<input type='hidden' name='db' value='%s'>\n", db); printf("<input type='hidden' name='%s' value=''>\n",TRACK_SEARCH_DEL_ROW); printf("<input type='hidden' name='%s' value=''>\n",TRACK_SEARCH_ADD_ROW); -#ifdef SUPPORT_COMPOSITE_SEARCH #ifdef USE_TABS printf("<input type='hidden' name='%s' id='currentTab' value='%s'>\n", FILE_SEARCH_CURRENT_TAB, currentTab); printf("<div id='tabs' style='display:none; %s'>\n" "<ul>\n" "<li><a href='#simpleTab'><B style='font-size:.9em;font-family: arial, Geneva, Helvetica, san-serif;'>Search</B></a></li>\n" "<li><a href='#filesTab'><B style='font-size:.9em;font-family: arial, Geneva, Helvetica, san-serif;'>Files</B></a></li>\n" "</ul>\n",cgiBrowser()==btIE?"width:1060px;":"max-width:inherit;"); // Files tab printf("<div id='simpleTab' style='max-width:inherit;'>\n"); printf("<table id='simpleTable' style='width:100%%; font-size:.9em;'><tr><td colspan='2'>"); printf("<input type='text' name='%s' id='simpleSearch' class='submitOnEnter' value='%s' style='max-width:1000px; width:100%%;' onkeyup='findTracksSearchButtonsEnable(true);'>\n", TRACK_SEARCH_SIMPLE,descSearch == NULL ? "" : descSearch); if (selectedTab==simpleTab && descSearch) searchTermsExist = TRUE; printf("</td></tr><td style='max-height:4px;'></td></tr></table>"); -//printf("</td></tr></table>"); printf("<input type='submit' name='%s' id='searchSubmit' value='search' style='font-size:.8em;'>\n", FILE_SEARCH); printf("<input type='button' name='clear' value='clear' class='clear' style='font-size:.8em;' onclick='findTracksClear();'>\n"); printf("<input type='submit' name='submit' value='cancel' class='cancel' style='font-size:.8em;'>\n"); printf("</div>\n"); -//#else///ifndef USE_TABS -//printf("<div id='noTabs' style='width:1060px;'>\n");//,cgiBrowser()==btIE?"width:1060px;":"max-width:inherit;"); #endif///def USE_TABS -#endif///def SUPPORT_COMPOSITE_SEARCH // Files tab printf("<div id='filesTab' style='width:inherit;'>\n" "<table id='filesTable' cellSpacing=0 style='width:inherit; font-size:.9em;'>\n"); cols = 8; -#ifdef SUPPORT_COMPOSITE_SEARCH -//// Track Name contains +// Track Name contains printf("<tr><td colspan=3></td>"); printf("<td nowrap><b style='max-width:100px;'>Track Name:</b></td>"); printf("<td align='right'>contains</td>\n"); printf("<td colspan='%d'>", cols - 4); printf("<input type='text' name='%s' id='nameSearch' class='submitOnEnter' value='%s' onkeyup='findTracksSearchButtonsEnable(true);' style='min-width:326px; font-size:.9em;'>", TRACK_SEARCH_ON_NAME, nameSearch == NULL ? "" : nameSearch); printf("</td></tr>\n"); // Description contains printf("<tr><td colspan=2></td><td align='right'>and </td>"); printf("<td><b style='max-width:100px;'>Description:</b></td>"); printf("<td align='right'>contains</td>\n"); printf("<td colspan='%d'>", cols - 4); printf("<input type='text' name='%s' id='descSearch' value='%s' class='submitOnEnter' onkeyup='findTracksSearchButtonsEnable(true);' style='max-width:536px; width:536px; font-size:.9em;'>", TRACK_SEARCH_ON_DESCR, descSearch == NULL ? "" : descSearch); @@ -397,39 +329,33 @@ for (; grp != NULL; grp = grp->next,ix++) { groups[ix] = cloneString(grp->name); labels[ix] = cloneString(grp->label); } printf("<tr><td colspan=2></td><td align='right'>and </td>\n"); printf("<td><b style='max-width:100px;'>Group:</b></td>"); printf("<td align='right'>is</td>\n"); printf("<td colspan='%d'>", cols - 4); char *groupSearch = cartOptionalString(cart, TRACK_SEARCH_ON_GROUP); cgiMakeDropListFull(TRACK_SEARCH_ON_GROUP, labels, groups, numGroups, groupSearch, "class='groupSearch' style='min-width:40%; font-size:.9em;'"); printf("</td></tr>\n"); if (selectedTab==filesTab && groupSearch) searchTermsExist = TRUE; -#endif///def SUPPORT_COMPOSITE_SEARCH // Track Type is (drop down) -#ifdef SUPPORT_COMPOSITE_SEARCH printf("<tr><td colspan=2></td><td align='right'>and </td>\n"); -#else///ifndef SUPPORT_COMPOSITE_SEARCH -printf("<tr><td colspan=2></td><td align='right'> </td>\n"); -#endif///ndef SUPPORT_COMPOSITE_SEARCH -//printf("<tr><td colspan=2></td><td align='right'>and </td>\n"); // Bring back "and" if using "Track Name,Description or Group printf("<td nowrap><b style='max-width:100px;'>Data Format:</b></td>"); printf("<td align='right'>is</td>\n"); printf("<td colspan='%d'>", cols - 4); char *dropDownHtml = fileFormatSelectHtml(FILE_SEARCH_ON_FILETYPE,fileTypeSearch,"style='min-width:40%; font-size:.9em;'"); if (dropDownHtml) { puts(dropDownHtml); freeMem(dropDownHtml); } printf("</td></tr>\n"); if (selectedTab==filesTab && fileTypeSearch) searchTermsExist = TRUE; // mdb selects struct slPair *mdbSelects = NULL; @@ -441,42 +367,40 @@ if (output) { puts(output); freeMem(output); } slPairFreeList(&mdbVars); } printf("</table>\n"); printf("<input type='submit' name='%s' id='searchSubmit' value='search' style='font-size:.8em;'>\n", FILE_SEARCH); printf("<input type='button' name='clear' value='clear' class='clear' style='font-size:.8em;' onclick='findTracksClear();'>\n"); printf("<input type='submit' name='submit' value='cancel' class='cancel' style='font-size:.8em;'>\n"); //printf("<a target='_blank' href='../goldenPath/help/trackSearch.html'>help</a>\n"); printf("</div>\n"); -#ifdef SUPPORT_COMPOSITE_SEARCH #ifdef USE_TABS printf("</div>\n"); // End tabs div #endif///def USE_TABS if(nameSearch != NULL && !strlen(nameSearch)) nameSearch = NULL; if(descSearch != NULL && !strlen(descSearch)) descSearch = NULL; if(groupSearch != NULL && sameString(groupSearch, ANYLABEL)) groupSearch = NULL; -#endif///def SUPPORT_COMPOSITE_SEARCH printf("</form>\n"); printf("</div>"); // Restricts to max-width:1000px; if (measureTiming) uglyTime("Rendered tabs"); #ifdef USE_TABS if (doSearch && selectedTab==simpleTab && isEmpty(descSearch)) doSearch = FALSE; #endif///def USE_TABS if(doSearch) { @@ -495,44 +419,42 @@ { enum sortBy sortBy = cartUsualInt(cart,TRACK_SEARCH_SORT,sbRelevance); int tracksFound = slCount(foundTdbs); if(tracksFound > 1) findTracksSort(&tracks,sortBy); displayFoundTracks(cart,tracks,tracksFound,sortBy); if (measureTiming) uglyTime("Displayed found files"); } } else if(selectedTab==filesTab && mdbPairs != NULL) #endif///def USE_TABS { - #ifdef SUPPORT_COMPOSITE_SEARCH if (nameSearch || descSearch || groupSearch) { // Use nameSearch, descSearch and groupSearch to narrow down the list of composites. if (isNotEmpty(nameSearch) || isNotEmpty(descSearch) || isNotEmpty(groupSearch)) { struct trackDb *tdbList = hTrackDb(db); struct trackDb *tdbsMatch = tdbFilterBy(&tdbList, nameSearch, descSearch, groupSearch); // Now we have a list of tracks, so we need a unique list of composites to add to mdbSelects doSearch = mdbSelectsAddFoundComposites(&mdbSelects,tdbsMatch); } } - #endif///def SUPPORT_COMPOSITE_SEARCH if (doSearch && mdbSelects != NULL && isNotEmpty(fileTypeSearch)) fileSearchResults(db, conn, mdbSelects, fileTypeSearch); else printf("<DIV id='filesFound'><BR>No files found.<BR></DIV><BR>\n"); if (measureTiming) uglyTime("Searched for files"); } slPairFreeList(&mdbSelects); } hFreeConn(&conn); webNewSection("About " FILE_SEARCH_NAME); @@ -584,16 +506,16 @@ char *excludeVars[] = { "submit", "Submit", "g", "ajax", FILE_SEARCH,TRACK_SEARCH_ADD_ROW,TRACK_SEARCH_DEL_ROW}; // HOW IS 'ajax" going to be supported? int main(int argc, char *argv[]) /* Process command line. */ { cgiSpoof(&argc, argv); htmlSetBackground(hBackgroundImage()); cartEmptyShell(doMiddle, hUserCookie(), excludeVars, NULL); return 0; } // TODO: // 1) Done: Limit to first 1000 // 2) Work out simple verses advanced tabs // 3) work out support for non-encode downloads -// 4) Make an hgTrackSearch to replces hgTracks track search ?? Silpler code, but may not be good idea. +// 4) Make an hgTrackSearch to replace hgTracks track search ?? Simlpler code, but may not be good idea because of composite reshaping in cart vars