7e5039db1d627eceaa4459dc4b25d2ced6f55fcc angie Tue Jul 28 08:55:57 2015 -0700 In groupedTrackDb, sort views alphabetically and subtracks by priority / shortLabel. diff --git src/hg/lib/cartJson.c src/hg/lib/cartJson.c index b1f44fb..d4f37ef 100644 --- src/hg/lib/cartJson.c +++ src/hg/lib/cartJson.c @@ -317,30 +317,49 @@ { 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 int trackDbViewCmp(const void *va, const void *vb) +/* *** I couldn't find anything like this in hgTracks or hui, but clearly views end up + * *** being ordered alphabetically somehow. Anyway... + * Compare two trackDbs, first by view if both have a view setting, then the usual way + * (by priority, then by shortLabel). */ +{ +const struct trackDb *a = *((struct trackDb **)va); +const struct trackDb *b = *((struct trackDb **)vb); +// The casts are necessary here unless one adds const to trackDbSetting decl +char *viewA = trackDbSetting((struct trackDb *)a, "view"); +char *viewB = trackDbSetting((struct trackDb *)b, "view"); +int diff = 0; +if (isNotEmpty(viewA) && isNotEmpty(viewB)) + diff = strcmp(viewA, viewB); +if (diff != 0) + return diff; +return trackDbCmp(va, vb); +} + 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 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]; @@ -358,30 +377,31 @@ if (tdbIsSuperTrackChild(tdb)) { // Supertracks have been omitted from fullTrackList, so add the supertrack object's // non-parent/child info here. jsonWriteObjectStart(jwNew, "parent"); writeTdbSimple(jwNew, tdb->parent, fieldHash); jsonWriteObjectEnd(jwNew); } else // Just the name so we don't have infinite loops. jsonWriteString(jwNew, "parent", tdb->parent->track); } if (doSubtracks) { jsonWriteListStart(jwNew, "subtracks"); + slSort(&tdb->subtracks, trackDbViewCmp); struct trackDb *subTdb; for (subTdb = tdb->subtracks; subTdb != NULL; subTdb = subTdb->next) { struct jsonWrite *jwSub = rTdbToJw(subTdb, fieldHash, excludeTypesHash, depth+1, maxDepth); if (jwSub) { gotSomething = TRUE; jsonWriteAppend(jwNew, NULL, jwSub); jsonWriteFree(&jwSub); } } jsonWriteListEnd(jwNew); } jsonWriteObjectEnd(jwNew); if (! gotSomething)