0fabc7d965abdc0b7901fe08dcdf873a305433ba angie Thu May 21 11:06:54 2015 -0700 hgIntegrator: omit bam and maf (wigMaf) tracks from the group/track/table menus because the underlying anno* libs don't support those types yet. refs #14579 note 52 diff --git src/hg/lib/cartJson.c src/hg/lib/cartJson.c index ba3ca2e..7284f95 100644 --- src/hg/lib/cartJson.c +++ src/hg/lib/cartJson.c @@ -317,63 +317,89 @@ { struct hashEl *hel; struct hashCookie cookie = hashFirst(tdb->settingsHash); while ((hel = hashNext(&cookie)) != NULL) { if (! nameIsTdbField(hel->name) && fieldOk(hel->name, fieldHash)) { //#*** TODO: move jsonStringEscape inside jsonWriteString char *encoded = jsonStringEscape((char *)hel->val); jsonWriteString(jw, hel->name, encoded); } } } } -static void rWriteTdb(struct jsonWrite *jw, struct trackDb *tdb, struct hash *fieldHash, - int depth, int maxDepth) -/* Recursively write JSON for tdb and its subtracks if any. If fieldHash is non-NULL, - * include only the field names indexed in fieldHash. */ +static struct jsonWrite *rTdbToJw(struct trackDb *tdb, struct hash *fieldHash, + struct hash *excludeTypesHash, int depth, int maxDepth) +/* Recursively build and return a new jsonWrite object with JSON for tdb and its children, + * or NULL if tdb or all children have been filtered out by excludeTypesHash. + * If excludeTypesHash is non-NULL, omit any tracks/views/subtracks with type in excludeTypesHash. + * If fieldHash is non-NULL, include only the field names indexed in fieldHash. */ { if (maxDepth >= 0 && depth > maxDepth) - return; -jsonWriteObjectStart(jw, NULL); -writeTdbSimple(jw, tdb, fieldHash); + return NULL; +boolean doSubtracks = (tdb->subtracks && fieldOk("subtracks", fieldHash)); +// If excludeTypesHash is given and tdb is a leaf track/subtrack, look up the first word +// of tdb->type in excludeTypesHash; if found, return NULL. +if (excludeTypesHash && !doSubtracks) + { + char typeCopy[PATH_LEN]; + safecpy(typeCopy, sizeof(typeCopy), tdb->type); + if (hashLookup(excludeTypesHash, firstWordInLine(typeCopy))) + return NULL; + } +boolean gotSomething = !doSubtracks; +struct jsonWrite *jwNew = jsonWriteNew(); +jsonWriteObjectStart(jwNew, NULL); +writeTdbSimple(jwNew, tdb, fieldHash); if (tdb->parent && fieldOk("parent", fieldHash)) { // We can't link to an object in JSON and better not recurse here or else infinite loop. if (tdbIsSuperTrackChild(tdb)) { // Supertracks have been omitted from fullTrackList, so add the supertrack object's // non-parent/child info here. - jsonWriteObjectStart(jw, "parent"); - writeTdbSimple(jw, tdb->parent, fieldHash); - jsonWriteObjectEnd(jw); + jsonWriteObjectStart(jwNew, "parent"); + writeTdbSimple(jwNew, tdb->parent, fieldHash); + jsonWriteObjectEnd(jwNew); } else // Just the name so we don't have infinite loops. - jsonWriteString(jw, "parent", tdb->parent->track); + jsonWriteString(jwNew, "parent", tdb->parent->track); } -if (tdb->subtracks && fieldOk("subtracks", fieldHash)) +if (doSubtracks) { - jsonWriteListStart(jw, "subtracks"); + jsonWriteListStart(jwNew, "subtracks"); struct trackDb *subTdb; for (subTdb = tdb->subtracks; subTdb != NULL; subTdb = subTdb->next) - rWriteTdb(jw, subTdb, fieldHash, depth+1, maxDepth); - jsonWriteListEnd(jw); + { + struct jsonWrite *jwSub = rTdbToJw(subTdb, fieldHash, excludeTypesHash, depth+1, maxDepth); + if (jwSub) + { + gotSomething = TRUE; + jsonWriteAppend(jwNew, NULL, jwSub); + jsonWriteFree(&jwSub); } -jsonWriteObjectEnd(jw); + } + jsonWriteListEnd(jwNew); + } +jsonWriteObjectEnd(jwNew); +if (! gotSomething) + // All children were excluded; clean up and null out jwNew. + jsonWriteFree(&jwNew); +return jwNew; } static struct hash *hashFromCommaString(char *commaString) /* Return a hash that stores words in comma-separated string, or NULL if string is NULL or empty. */ { struct hash *hash = NULL; if (isNotEmpty(commaString)) { hash = hashNew(0); char *words[1024]; int i, wordCount = chopCommas(commaString, words); for (i = 0; i < wordCount; i++) hashStoreName(hash, words[i]); } return hash; @@ -408,85 +434,109 @@ struct trackDb *a = aRef->val, *b = bRef->val; return trackDbCmpShortLabel(&a, &b); } static struct slRef *sortedAllTracks(struct trackDb *trackList) /* Return an slRef list containing all tdbs in track list, sorted by shortLabel. */ { struct slRef *trackRefList = NULL; struct trackDb *tdb; for (tdb = trackList; tdb != NULL; tdb = tdb->next) slAddHead(&trackRefList, slRefNew(tdb)); slSort(&trackRefList, trackDbRefCmpShortLabel); return trackRefList; } -static void writeGroupedTrack(struct jsonWrite *jw, char *name, char *label, struct hash *fieldHash, +static boolean writeGroupedTrack(struct jsonWrite *jw, char *name, char *label, + struct hash *fieldHash, struct hash *excludeTypesHash, int maxDepth, struct slRef *tdbRefList) -{ -jsonWriteObjectStart(jw, NULL); -jsonWriteString(jw, "name", name); -jsonWriteString(jw, "label", label); -jsonWriteListStart(jw, "tracks"); +/* If tdbRefList is empty after excluding tracks/views/subtracks whose types are + * in excludeTypesHash, then return FALSE and write nothing. Otherwise write a group + * and its tracks/views/subtracks and return TRUE. */ +{ +// Make a new jsonWrite object in case this group turns out to have no children after filtering. +struct jsonWrite *jwNew = jsonWriteNew(); +jsonWriteObjectStart(jwNew, NULL); +jsonWriteString(jwNew, "name", name); +jsonWriteString(jwNew, "label", label); +jsonWriteListStart(jwNew, "tracks"); +boolean gotSomething = FALSE; struct slRef *tdbRef; for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) { struct trackDb *tdb = tdbRef->val; - rWriteTdb(jw, tdb, fieldHash, 1, maxDepth); + // First see if there are any tracks to show for this group: + struct jsonWrite *jwTrack = rTdbToJw(tdb, fieldHash, excludeTypesHash, 1, maxDepth); + if (jwTrack) + { + gotSomething = TRUE; + jsonWriteAppend(jwNew, NULL, jwTrack); + jsonWriteFree(&jwTrack); } -jsonWriteListEnd(jw); -jsonWriteObjectEnd(jw); + } +if (gotSomething) + { + // Group has at least one track, so append it to jw. + jsonWriteListEnd(jwNew); + jsonWriteObjectEnd(jwNew); + jsonWriteAppend(jw, NULL, jwNew); + } +jsonWriteFree(&jwNew); +return gotSomething; } void cartJsonGetGroupedTrackDb(struct cartJson *cj, struct hash *paramHash) /* Translate trackDb list (only a subset of the fields) into JSON array of track group objects; * each group contains an array of track objects that may have subtracks. Send it in a wrapper * object that includes the database from which it was taken; it's possible that by the time * this reaches the client, the user might have switched to a new db. */ { struct trackDb *fullTrackList = NULL; struct grp *fullGroupList = NULL; cartTrackDbInit(cj->cart, &fullTrackList, &fullGroupList, /* useAccessControl=*/TRUE); struct hash *groupedTrackRefList = hashTracksByGroup(fullTrackList); // If the optional param 'fields' is given, hash the field names that should be returned. char *fields = cartJsonOptionalParam(paramHash, "fields"); struct hash *fieldHash = hashFromCommaString(fields); +char *excludeTypes = cartJsonOptionalParam(paramHash, "excludeTypes"); +struct hash *excludeTypesHash = hashFromCommaString(excludeTypes); // Also check for optional parameter 'maxDepth': int maxDepth = -1; char *maxDepthStr = cartJsonOptionalParam(paramHash, "maxDepth"); if (isNotEmpty(maxDepthStr)) maxDepth = atoi(maxDepthStr); struct jsonWrite *jw = cj->jw; jsonWriteObjectStart(jw, "groupedTrackDb"); jsonWriteString(jw, "db", cartString(cj->cart, "db")); jsonWriteListStart(jw, "groupedTrackDb"); int nonEmptyGroupCount = 0; struct grp *grp; for (grp = fullGroupList; grp != NULL; grp = grp->next) { struct slRef *tdbRefList = hashFindVal(groupedTrackRefList, grp->name); - if (tdbRefList) + if (writeGroupedTrack(jw, grp->name, grp->label, fieldHash, excludeTypesHash, + maxDepth, tdbRefList)) { nonEmptyGroupCount++; - writeGroupedTrack(jw, grp->name, grp->label, fieldHash, maxDepth, tdbRefList); } } if (nonEmptyGroupCount == 0) { // Catch-all for assembly hubs that don't declare groups for their tracks: add All Tracks struct slRef *allTracks = sortedAllTracks(fullTrackList); - writeGroupedTrack(jw, "allTracks", "All Tracks", fieldHash, maxDepth, allTracks); + (void)writeGroupedTrack(jw, "allTracks", "All Tracks", fieldHash, excludeTypesHash, + maxDepth, allTracks); } jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); } static char *hAssemblyDescription(char *db) /* Return a string containing db's description.html, or NULL if not found. */ //#*** LIBIFY: Code lifted from hgFind.c's hgPositionsHelpHtml. { char *htmlPath = hHtmlPath(db); char *htmlString = NULL; if (htmlPath != NULL) { if (fileExists(htmlPath)) readInGulp(htmlPath, &htmlString, NULL);