26e823952cab1684e88762b035e3369f17e887ca tdreszer Tue Mar 15 09:46:32 2011 -0700 Added search for composites by name, desc and group. diff --git src/hg/hgFileSearch/hgFileSearch.c src/hg/hgFileSearch/hgFileSearch.c index 952f499..29b2252 100644 --- src/hg/hgFileSearch/hgFileSearch.c +++ src/hg/hgFileSearch/hgFileSearch.c @@ -1,472 +1,501 @@ #include "common.h" #include "hash.h" #include "cheapcgi.h" #include "htmshell.h" #include "jsHelper.h" #include "trackDb.h" #include "hdb.h" #include "web.h" #include "mdb.h" #include "hCommon.h" #include "hui.h" #include "fileUi.h" #include "searchTracks.h" #include "cart.h" #include "grp.h" #define FAKE_MDB_MULTI_SELECT_SUPPORT struct hash *trackHash = NULL; // Is this needed? boolean measureTiming = FALSE; /* DON'T EDIT THIS -- use CGI param "&measureTiming=." . */ #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 -//#define SUPPORT_COMPOSITE_SEARCH +#endif///def SUPPORT_COMPOSITE_SEARCH -#ifdef OMIT_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)) || -static boolean isNameMatch(struct trackDb *tdb, char *str, char *op) +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). { -return str && strlen(str) && - ((sameString(op, "is") && !strcasecmp(tdb->shortLabel, str)) || - (sameString(op, "is") && !strcasecmp(tdb->longLabel, str)) || - (sameString(op, "contains") && containsStringNoCase(tdb->shortLabel, str) != NULL) || - (sameString(op, "contains") && containsStringNoCase(tdb->longLabel, str) != NULL)); -} +if (tdb->html == NULL) + return (wordList != NULL); -static boolean isDescriptionMatch(struct trackDb *tdb, char **words, int wordCount) -// We parse str and look for every word at the start of any word in track description (i.e. google style). +struct slName *word = wordList; +for(; word != NULL; word = word->next) { -if(words) + if (!wildMatch(word->name, tdb->html)) + return FALSE; + } +return TRUE; +} + +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 { - // We do NOT lookup up parent hierarchy for html descriptions. - char *html = tdb->html; - if(!isEmpty(html)) +// Set the word list up once +struct slName *wordList = NULL; +if (description) + wordList = slNameListOfUniqueWords(cloneString(description)); + +struct trackDb *tdbList = *pTdbList; +struct trackDb *tdbRejects = NULL; +struct trackDb *tdbMatched = NULL; +while (tdbList != NULL) { - // This probably could be made more efficient by parsing the html into some kind of b-tree, but I am assuming - // that the inner html loop while only happen for 1-2 words for vast majority of the tracks. + struct trackDb *tdb = slPopHead(&tdbList); + + if (name && (!wildMatch(name,tdb->shortLabel) && !wildMatch(name,tdb->longLabel))) + slAddHead(&tdbRejects,tdb); + else if (group && differentString(tdb->grp,group)) + slAddHead(&tdbRejects,tdb); + else if (description && !isDescriptionMatch(tdb, wordList)) + slAddHead(&tdbRejects,tdb); + else + slAddHead(&tdbMatched,tdb); + } +//slReverse(&tdbRejects); // Needed? +//slReverse(&tdbMatched); // Needed? + +*pTdbList = tdbRejects; - int i, numMatches = 0; - html = stripRegEx(html, "<[^>]*>", REG_ICASE); - for(i = 0; i < wordCount; i++) +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. { - char *needle = words[i]; - char *haystack, *tmp = cloneString(html); - boolean found = FALSE; - while((haystack = nextWord(&tmp))) +// create comma separated list of composites +struct dyString *dyComposites = dyStringNew(256); +struct trackDb *tdb = tdbsFound; +for(;tdb != NULL; tdb = tdb->next) { - char *ptr = strstrNoCase(haystack, needle); - if(ptr != NULL && ptr == haystack) + if (tdbIsComposite(tdb)) + dyStringPrintf(dyComposites,"%s,",tdb->track); + else if (tdbIsCompositeChild(tdb)) { - found = TRUE; - break; + struct trackDb *composite = tdbGetComposite(tdb); + dyStringPrintf(dyComposites,"%s,",composite->track); } } - if(found) - numMatches++; - else - break; - } - if(numMatches == wordCount) +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 return TRUE; } - } + +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 { 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; *grps = NULL; 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) { 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); -char *descSearch=FALSE; boolean doSearch = sameWord(cartUsualString(cart, FILE_SEARCH,"no"), "search"); struct sqlConnection *conn = hAllocConn(db); boolean metaDbExists = sqlTableExists(conn, "metaDb"); #ifdef ONE_FUNC struct hash *parents = newHash(4); #endif///def ONE_FUNC -char **descWords = NULL; -int descWordCount = 0; 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); - #ifdef SUPPORT_COMPOSITE_SEARCH freez(&nameSearch); - #endif///def SUPPORT_COMPOSITE_SEARCH } 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 if(descSearch) stripChar(descSearch, '"'); #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("