21e19f9c3bb9592c558c3984ed78cae6c13feb4f tdreszer Wed Mar 23 15:13:44 2011 -0700 Fixed bug on name/description search and fleshed out wild card and quoted strings in description search diff --git src/hg/hgFileSearch/hgFileSearch.c src/hg/hgFileSearch/hgFileSearch.c index d44d3b8..3850764 100644 --- src/hg/hgFileSearch/hgFileSearch.c +++ src/hg/hgFileSearch/hgFileSearch.c @@ -29,101 +29,125 @@ #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 DESCRIPTION_MATCH_ON_EACH_WORD +#ifdef DESCRIPTION_MATCH_ON_EACH_WORD static boolean isDescriptionMatch(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) return (wordList != NULL); struct slName *word = wordList; for(; word != NULL; word = word->next) { - if (!wildMatch(word->name, tdb->html)) + char wordWild[256]; + safef(wordWild,sizeof wordWild,"*%s*",word->name); + if (!wildMatch(wordWild, tdb->html)) return FALSE; } return TRUE; } +#endif///def DESCRIPTION_MATCH_ON_EACH_WORD -static struct trackDb *tdbFilterOn(struct trackDb **pTdbList, char *name, char *description, char *group) -// returns tdbs that pach supplied criterion, leaving unmatched in list passed in +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 DESCRIPTION_MATCH_ON_EACH_WORD // Set the word list up once struct slName *wordList = NULL; if (description) - wordList = slNameListOfUniqueWords(cloneString(description)); + wordList = slNameListOfUniqueWords(cloneString(description),TRUE); // TRUE means respect quotes +#endif///def DESCRIPTION_MATCH_ON_EACH_WORD struct trackDb *tdbList = *pTdbList; struct trackDb *tdbRejects = NULL; struct trackDb *tdbMatched = NULL; +char nameWild[256]; +if (name) + safef(nameWild,sizeof nameWild,"*%s*",name); +#ifndef DESCRIPTION_MATCH_ON_EACH_WORD +char descWild[512]; +if (description) + safef(descWild,sizeof descWild,"*%s*",description); +#endif///ndef DESCRIPTION_MATCH_ON_EACH_WORD + while (tdbList != NULL) { struct trackDb *tdb = slPopHead(&tdbList); - if (name && (!wildMatch(name,tdb->shortLabel) && !wildMatch(name,tdb->longLabel))) + if (name && (!wildMatch(nameWild,tdb->shortLabel) && !wildMatch(nameWild,tdb->longLabel))) slAddHead(&tdbRejects,tdb); else if (group && differentString(tdb->grp,group)) slAddHead(&tdbRejects,tdb); +#ifdef DESCRIPTION_MATCH_ON_EACH_WORD else if (description && !isDescriptionMatch(tdb, wordList)) +#else///ifndef DESCRIPTION_MATCH_ON_EACH_WORD + else if (description && (tdb->html == NULL || !wildMatch(descWild,tdb->html))) +#endif///ndef DESCRIPTION_MATCH_ON_EACH_WORD slAddHead(&tdbRejects,tdb); 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) { if (tdbIsComposite(tdb)) dyStringPrintf(dyComposites,"%s,",tdb->track); else if (tdbIsCompositeChild(tdb)) { struct trackDb *composite = tdbGetComposite(tdb); dyStringPrintf(dyComposites,"%s,",composite->track); } } if (dyStringLen(dyComposites) > 0) { char *composites = dyStringCannibalize(&dyComposites); composites[strlen(composites) - 1] = '\0'; // drop the last ',' - slPairAdd(pMdbSelects,"composite",composites); // Composite should not already be in the list, because it is only indirectly sortable + //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); @@ -158,31 +182,31 @@ struct slName *tdbGroups = tdbListGetGroups(tdbList); if (tdbList == NULL) return *grps; while (grpList != NULL) { struct grp *grp = slPopHead(&grpList); if (slNameInList(tdbGroups,grp->name)) slAddHead(grps,grp); } slNameFreeList(&tdbGroups); slReverse(grps); return *grps; } -void doSearch(char *db,char *organism,struct cart *cart,struct trackDb *tdbList) +static void doFileSearch(char *db,struct cart *cart,struct trackDb *tdbList) { if (!advancedJavascriptFeaturesEnabled(cart)) { warn("Requires advanced javascript features."); 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"); struct sqlConnection *conn = hAllocConn(db); boolean metaDbExists = sqlTableExists(conn, "metaDb"); #ifdef ONE_FUNC @@ -199,32 +223,34 @@ { 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 DESCRIPTION_MATCH_ON_EACH_WORD if(descSearch) stripChar(descSearch, '"'); +#endif///ndef DESCRIPTION_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()); @@ -404,39 +430,46 @@ 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 = tdbFilterOn(&tdbList, nameSearch, descSearch, groupSearch); + 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 - mdbSelectsAddFoundComposites(&mdbSelects,tdbsMatch); + 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 Downloadable Files Search"); if(metaDbExists) printf("<p>Search for terms in track names, descriptions, groups, and ENCODE " "metadata. If multiple terms are entered, only tracks with all terms " "will be part of the results."); else printf("<p>Search for terms in track descriptions, groups, and names. " @@ -462,31 +495,31 @@ cartWebStart(cart, db, "Search for Downloadable Files in the %s %s Assembly", organism, hFreezeFromDb(db)); webIncludeResourceFile("HGStyle.css"); webIncludeResourceFile("jquery-ui.css"); webIncludeResourceFile("ui.dropdownchecklist.css"); jsIncludeFile("jquery.js", NULL); jsIncludeFile("jquery-ui.js", NULL); //jsIncludeFile("ui.core.js",NULL); // NOTE: This appears to be not needed as long as jquery-ui.js comes before ui.dropdownchecklist.js jsIncludeFile("ui.dropdownchecklist.js",NULL); jsIncludeFile("utils.js",NULL); // This line is needed to get the multi-selects initialized //printf("<script type='text/javascript'>$(document).ready(function() { setTimeout('updateMetaDataHelpLinks(0);',50); $('.filterBy').each( function(i) { $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true });});});</script>\n"); printf("<script type='text/javascript'>$(document).ready(function() { updateMetaDataHelpLinks(0); $('.filterBy').each( function(i) { $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true });});});</script>\n"); -doSearch(db,organism,cart,tdbList); +doFileSearch(db,cart,tdbList); printf("<BR>\n"); webEnd(); } 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;