0bd11409624970f87f46089c184f38bc9360f136 braney Sat Mar 10 11:18:22 2018 -0800 make sure auto-generated short labels are unique within the collection diff --git src/hg/hgCollection/hgCollection.c src/hg/hgCollection/hgCollection.c index afd925e..7cccd6f 100644 --- src/hg/hgCollection/hgCollection.c +++ src/hg/hgCollection/hgCollection.c @@ -41,31 +41,56 @@ char *visibility; unsigned long color; char *viewFunc; // The method by which calculated tracks should be calculated char *missingMethod; // How should missing data be treated in calculated tracks }; struct trackDbRef { struct trackDbRef *next; struct trackDb *tdb; struct grp *grp; double priority; int order; }; -static char *makeUnique(struct hash *nameHash, char *name) +static char *makeUniqueLabel(struct hash *labelHash, char *label) +// Make the short label of this track unique. +{ +if (hashLookup(labelHash, label) == NULL) + { + hashStore(labelHash, label); + return label; + } + +unsigned count = 1; +char buffer[4096]; + +for(;; count++) + { + safef(buffer, sizeof buffer, "%s (%d)", label, count); + if (hashLookup(labelHash, buffer) == NULL) + { + hashStore(labelHash, buffer); + return cloneString(buffer); + } + } + +return NULL; +} + +static char *makeUniqueName(struct hash *nameHash, char *name) // Make the name of this track unique. { char *skipHub = trackHubSkipHubName(name); if (hashLookup(nameHash, skipHub) == NULL) { hashStore(nameHash, name); return skipHub; } char base[4096]; safef(base, sizeof base, "%s_%lx",skipHub, time(NULL) - 1520629086); unsigned count = 0; char buffer[4096]; @@ -361,65 +386,69 @@ struct hash *groupHash = newHash(10); int count = 0; for(curGroup = groupList; curGroup; curGroup = curGroup->next) { if (curGroup->priority == 0) curGroup->priority = count--; hashAdd(groupHash, curGroup->name, curGroup); } curGroup = NULL; if (hubName != NULL) curGroup = hashFindVal(groupHash, hubName); jsInlineF("var collectionData = []; "); -struct dyString *dy = newDyString(1024); +struct dyString *dyNames = newDyString(1024); +struct dyString *dyLabels = newDyString(1024); jsInlineF("var collectionNames = [];"); +jsInlineF("var collectionLabels = [];"); if (curGroup != NULL) { // print out all the tracks in all the collections struct trackDb *tdb; jsInlineF("collectionData['#'] = ["); boolean first = TRUE; for(tdb = trackList; tdb; tdb = tdb->next) { if (sameString(tdb->grp, hubName)) { if (!first) { jsInlineF(","); } printTrack("#", tdb, TRUE); - dyStringPrintf(dy, "collectionNames['%s']=1;", trackHubSkipHubName(tdb->track)); + dyStringPrintf(dyNames, "collectionNames['%s']=1;", trackHubSkipHubName(tdb->track)); + dyStringPrintf(dyLabels, "collectionLabels['%s']=1;", tdb->shortLabel); first = FALSE; } } jsInlineF("];"); for(tdb = trackList; tdb; tdb = tdb->next) { if ( sameString(tdb->grp, curGroup->name)) { printSubtracks("collectionData", tdb, TRUE); - addSubtrackNames(dy, tdb); + addSubtrackNames(dyNames, tdb); } } } else jsInlineF("collectionData['#'] = [];"); -jsInlineF("%s", dy->string); +jsInlineF("%s", dyNames->string); +jsInlineF("%s", dyLabels->string); jsInlineF("var trackData = []; "); struct dyString *rootChildren = newDyString(512); addVisibleTracks(groupHash, rootChildren, cart, trackList); for(curGroup = groupList; curGroup; curGroup = curGroup->next) { if ((hubName != NULL) && sameString(curGroup->name, hubName)) continue; if (!isEmpty(rootChildren->string)) dyStringPrintf(rootChildren, ","); dyStringPrintf(rootChildren, "{icon:'../images/folderC.png',id:'%s', text:'%s', parent:'#', children:true,li_attr:{title:'%s'}}", curGroup->name, curGroup->label, FOLDERTITLE); struct trackDb *tdb; jsInlineF("trackData['%s'] = [", curGroup->name); boolean first = TRUE; for(tdb = trackList; tdb; tdb = tdb->next) @@ -566,31 +595,31 @@ if (conn == NULL) errAbort("track hub has bigWig without bigDataUrl"); dataUrl = getSqlBigWig(conn, db, tdb); hashReplace(tdb->settingsHash, "bigDataUrl", dataUrl); } } char *tdbType = trackDbSetting(tdb, "tdbType"); if (tdbType != NULL) hashReplace(tdb->settingsHash, "type", tdbType); hashRemove(tdb->settingsHash, "superTrack"); hashReplace(tdb->settingsHash, "parent", parent); hashReplace(tdb->settingsHash, "shortLabel", track->shortLabel); hashReplace(tdb->settingsHash, "longLabel", track->longLabel); -hashReplace(tdb->settingsHash, "track", makeUnique(collectionNameHash, name)); +hashReplace(tdb->settingsHash, "track", makeUniqueName(collectionNameHash, name)); char priBuf[128]; safef(priBuf, sizeof priBuf, "%d", priority); hashReplace(tdb->settingsHash, "priority", cloneString(priBuf)); char colorString[64]; safef(colorString, sizeof colorString, "%d,%d,%d", (color >> 16) & 0xff,(color >> 8) & 0xff,color & 0xff); hashReplace(tdb->settingsHash, "color", colorString); struct dyString *dy = trackDbString(tdb); fprintf(f, "%s", dy->string); fprintf(f, "\n"); } static void outComposite(FILE *f, struct track *collection, int priority) // output a composite header for user composite @@ -785,40 +814,42 @@ slReverse(&collectionList); return collectionList; } static void doAjax(struct cart *cart, char *db, char *jsonText, struct hash *nameHash) // Save our state { cgiDecodeFull(jsonText, jsonText, strlen(jsonText)); struct jsonElement *collectionElements = jsonParse(jsonText); struct track *collectionList = parseJsonElements(collectionElements); updateHub(cart, db, collectionList, nameHash); } -static void buildNameHash(struct hash *nameHash, struct trackDb *list) +static void buildNameHash(struct hash *nameHash, struct hash *labelHash, struct trackDb *list) { if (list == NULL) return; struct trackDb *tdb = list; for(tdb = list; tdb; tdb = tdb->next) { hashAdd(nameHash, trackHubSkipHubName(tdb->track), tdb); - buildNameHash(nameHash, tdb->subtracks); + if (labelHash) + hashAdd(labelHash, tdb->shortLabel, tdb); + buildNameHash(nameHash, NULL, tdb->subtracks); } } static struct trackDb *traverseTree(struct trackDb *oldList, struct hash *groupHash) // add acceptable tracks to our tree { struct trackDb *newList = NULL, *tdb, *tdbNext; for(tdb = oldList; tdb ; tdb = tdbNext) { tdbNext = tdb->next; if (tdb->subtracks) { tdb->subtracks = traverseTree(tdb->subtracks, groupHash); @@ -972,37 +1003,37 @@ } } static void doAddTrack(struct cart *cart, char *db, struct trackDb *trackList, char *trackName, char *collectionName, struct hash *nameHash) /* Add a track to a collection in a hub. */ { char *fileName = getHubName(cart, db); char *hubName = hubNameFromUrl(fileName); FILE *f = fopen(fileName, "w"); struct trackDb *newTdb = hashMustFindVal(nameHash, trackHubSkipHubName(trackName)); if (newTdb->subtracks) { struct trackDb *subTdb; for(subTdb = newTdb->subtracks; subTdb; subTdb = subTdb->next) { - hashReplace(subTdb->settingsHash, "track", makeUnique(nameHash, subTdb->track)); + hashReplace(subTdb->settingsHash, "track", makeUniqueName(nameHash, subTdb->track)); hashReplace(subTdb->settingsHash, "parent", trackHubSkipHubName(collectionName)); } } else { - hashReplace(newTdb->settingsHash, "track", makeUnique(nameHash, trackName)); + hashReplace(newTdb->settingsHash, "track", makeUniqueName(nameHash, trackName)); hashReplace(newTdb->settingsHash, "parent", trackHubSkipHubName(collectionName)); } char *tdbType = trackDbSetting(newTdb, "tdbType"); if (tdbType != NULL) { hashReplace(newTdb->settingsHash, "type", tdbType); hashReplace(newTdb->settingsHash, "shortLabel", trackDbSetting(newTdb, "name")); hashReplace(newTdb->settingsHash, "longLabel", trackDbSetting(newTdb, "description")); } outHubHeader(f, db); struct sqlConnection *conn = NULL; if (!trackHubDatabase(db)) conn = hAllocConn(db); @@ -1020,50 +1051,53 @@ char *genome; getDbAndGenome(cart, &db, &genome, oldVars); initGenbankTableNames(db); int timeout = cartUsualInt(cart, "udcTimeout", 300); if (udcCacheTimeout() < timeout) udcSetCacheTimeout(timeout); knetUdcInstall(); struct trackDb *trackList; struct grp *groupList; cartTrackDbInit(cart, &trackList, &groupList, TRUE); pruneTrackList(&trackList, &groupList); struct trackDb *superList = addSupers(trackList); struct hash *nameHash = newHash(5); -buildNameHash(nameHash, superList); +struct hash *labelHash = newHash(5); +buildNameHash(nameHash, labelHash, superList); char *cmd = cartOptionalString(cart, "cmd"); if (cmd == NULL) { doMainPage(cart, db, groupList, superList); } else if (sameString("addTrack", cmd)) { char *trackName = cgiString("track"); char *collectionName = cgiString("collection"); doAddTrack(cart, db, superList, trackName, collectionName, nameHash); apiOut("{\"serverSays\": \"added %s to collection\"}", NULL); } else if (sameString("newCollection", cmd)) { char *trackName = cgiString("track"); - char *collectionName = makeUnique(nameHash, "coll"); - char *shortLabel = "New Collection"; - char *longLabel = "Description of New Collection"; + char *collectionName = makeUniqueName(nameHash, "coll"); + char *shortLabel = makeUniqueLabel(labelHash, "New Collection"); + char buffer[4096]; + safef(buffer, sizeof buffer, "%s description", shortLabel); + char *longLabel = cloneString(buffer); struct trackDb *tdb; AllocVar(tdb); slAddHead(&superList, tdb); tdb->settingsHash = newHash(5); tdb->type = cloneString("wig"); hashAdd(tdb->settingsHash, "track", collectionName); hashAdd(tdb->settingsHash, "shortLabel", shortLabel); hashAdd(tdb->settingsHash, "longLabel", longLabel); hashAdd(tdb->settingsHash, "autoScale", "on"); hashAdd(tdb->settingsHash, "compositeTrack", "on"); hashAdd(tdb->settingsHash, "aggregate", "none"); hashAdd(tdb->settingsHash, "type", "mathWig"); hashAdd(tdb->settingsHash, "visibility", "full");