5b1c3cb6e7ce60e71edfb9e7237eca2fe7a02910
braney
Wed Apr 18 15:45:25 2018 -0700
fixed bug #21294 by re-introducing some code that checks to see if a
name has already been used before appending some uniqueifying text
diff --git src/hg/hgCollection/hgCollection.c src/hg/hgCollection/hgCollection.c
index a58bfd7..1960bdb 100644
--- src/hg/hgCollection/hgCollection.c
+++ src/hg/hgCollection/hgCollection.c
@@ -1,1059 +1,1066 @@
/* hgCollection - hub builder */
/* Copyright (C) 2017 The Regents of the University of California
* See README in this or parent directory for licensing information. */
#include "common.h"
#include "cartTrackDb.h"
#include "trackHub.h"
#include "trashDir.h"
#include "hubConnect.h"
#include "hui.h"
#include "grp.h"
#include "cheapcgi.h"
#include "jsHelper.h"
#include "web.h"
#include "knetUdc.h"
#include "api.h"
#include "genbank.h"
#include "htmshell.h"
#include "jsonParse.h"
#include "customComposite.h"
#include "stdlib.h"
/* Tool tips */
#define COLLECTION_TITLE "Double-click to edit name and color"
#define FOLDER_TITLE "Click to open node"
#define TRACK_TITLE "Press Green Plus to add track to collection"
/* Global Variables */
struct hash *oldVars = NULL; /* The cart before new cgi stuff added. */
// Null terminated list of CGI Variables we don't want to save permanently:
char *excludeVars[] = {"Submit", "submit", "cmd", "track", "collection", "jsonp", NULL,};
struct track
{
struct track *next;
struct track *trackList;
struct trackDb *tdb;
char *name;
char *shortLabel;
char *longLabel;
unsigned long color;
};
struct trackDbRef
{
struct trackDbRef *next;
struct trackDb *tdb;
struct grp *grp;
double priority;
int order;
};
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, skipHub);
+ return skipHub;
+ }
+
char base[4096];
safef(base, sizeof base, "%s_%lx",skipHub, time(NULL) - 1520629086);
unsigned count = 0;
char buffer[4096];
for(;; count++)
{
safef(buffer, sizeof buffer, "%s%d", base, count);
if (hashLookup(nameHash, buffer) == NULL)
{
hashStore(nameHash, buffer);
return cloneString(buffer);
}
}
return NULL;
}
static struct trackDb *createComposite(char *collectionName, char *shortLabel, char *longLabel, long color, int priority)
// Create a trackDb entry for a new composite
{
struct trackDb *tdb;
char buffer[512];
AllocVar(tdb);
tdb->settingsHash = newHash(5);
tdb->type = cloneString("mathWig");
safef(buffer, sizeof buffer, "%ld,%ld,%ld", 0xff & (color >> 16),0xff & (color >> 8),0xff & color);
hashAdd(tdb->settingsHash, "color", cloneString(buffer));
safef(buffer, sizeof buffer, "%d", priority);
hashAdd(tdb->settingsHash, "priority", cloneString(buffer));
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");
hashAdd(tdb->settingsHash, "customized", "on");
hashAdd(tdb->settingsHash, "maxHeightPixels", "10000:30:11");
hashAdd(tdb->settingsHash, "showSubtrackColorOnUi", "on");
hashAdd(tdb->settingsHash, CUSTOM_COMPOSITE_SETTING, "on");
return tdb;
}
static boolean trackCanBeAdded(struct trackDb *tdb)
// are we allowing this track into a custom composite
{
return (tdb->subtracks == NULL) && !startsWith("wigMaf",tdb->type) && (startsWith("wig",tdb->type) || startsWith("bigWig",tdb->type) || startsWith("bedGraph",tdb->type)) ;
}
static char *escapeLabel(char *label)
// put a blackslash in front of any single quotes in the input
{
char buffer[4096], *eptr = buffer;
for(; *label; label++)
{
if (*label == '\'')
{
*eptr++ = '\\';
*eptr++ = '\'';
}
else
*eptr++ = *label;
}
*eptr = 0;
return cloneString(buffer);
}
static void trackToClient(char *parent, struct trackDb *tdb, boolean user)
// output list elements for a group
{
char *userString = "";
char *title;
if (user)
title = COLLECTION_TITLE;
else if (tdb->subtracks)
title = FOLDER_TITLE;
else
title = TRACK_TITLE;
if (tdb->subtracks)
userString = "icon:'../images/folderC.png',children:true,";
else if (user)
userString = "icon:'fa fa-minus-square',";
else
userString = "icon:'fa fa-plus',";
#define IMAKECOLOR_32(r,g,b) ( ((unsigned int)b<<0) | ((unsigned int)g << 8) | ((unsigned int)r << 16))
jsInlineF("{%s id:'%s',li_attr:{title:'%s',shortlabel:'%s', longlabel:'%s',color:'#%06x',name:'%s'},text:'%s (%s)',parent:'%s'}",userString, trackHubSkipHubName(tdb->track),title, escapeLabel(tdb->shortLabel), escapeLabel(tdb->longLabel), IMAKECOLOR_32(tdb->colorR,tdb->colorG,tdb->colorB),trackHubSkipHubName(tdb->track),escapeLabel(tdb->shortLabel),escapeLabel(tdb->longLabel),parent);
}
static void outHubHeader(FILE *f, char *db)
// output a track hub header
{
fprintf(f,"hub hub1\n\
shortLabel Track Collections\n\
longLabel Track Collections\n\
useOneFile on\n\
email genome-www@soe.ucsc.edu\n\n");
fprintf(f,"genome %s\n\n", db);
}
static char *getHubName(struct cart *cart, char *db)
// get the name of the hub to use for user collections
{
struct tempName hubTn;
char buffer[4096];
safef(buffer, sizeof buffer, "%s-%s", customCompositeCartName, db);
char *hubName = cartOptionalString(cart, buffer);
int fd = -1;
if ((hubName == NULL) || ((fd = open(hubName, 0)) < 0))
{
trashDirDateFile(&hubTn, "hgComposite", "hub", ".txt");
hubName = cloneString(hubTn.forCgi);
cartSetString(cart, buffer, hubName);
FILE *f = mustOpen(hubName, "a");
outHubHeader(f, db);
fclose(f);
}
if (fd >= 0)
close(fd);
cartSetString(cart, "hubUrl", hubName);
cartSetString(cart, hgHubConnectRemakeTrackHub, hubName);
return hubName;
}
static bool subtrackEnabledInTdb(struct trackDb *subTdb)
/* Return TRUE unless the subtrack was declared with "subTrack ... off". */
{
bool enabled = TRUE;
char *words[2];
char *setting;
if ((setting = trackDbLocalSetting(subTdb, "parent")) != NULL)
{
if (chopLine(cloneString(setting), words) >= 2)
if (sameString(words[1], "off"))
enabled = FALSE;
}
else
return subTdb->visibility != tvHide;
return enabled;
}
static bool isSubtrackVisible(struct cart *cart, struct trackDb *tdb)
/* Has this subtrack not been deselected in hgTrackUi or declared with
* * "subTrack ... off"? -- assumes composite track is visible. */
{
boolean overrideComposite = (NULL != cartOptionalString(cart, tdb->track));
bool enabledInTdb = subtrackEnabledInTdb(tdb);
char option[1024];
safef(option, sizeof(option), "%s_sel", tdb->track);
boolean enabled = cartUsualBoolean(cart, option, enabledInTdb);
if (overrideComposite)
enabled = TRUE;
return enabled;
}
static bool isParentVisible(struct cart *cart, struct trackDb *tdb)
// Are this track's parents visible?
{
if (tdb->parent == NULL)
return TRUE;
if (!isParentVisible(cart, tdb->parent))
return FALSE;
char *cartVis = cartOptionalString(cart, tdb->parent->track);
boolean vis;
if (cartVis != NULL)
vis = differentString(cartVis, "hide");
else if (tdbIsSuperTrack(tdb->parent))
vis = tdb->parent->isShow;
else
vis = tdb->parent->visibility != tvHide;
return vis;
}
static void checkForVisible(struct cart *cart, struct grp *grp, struct trackDbRef **list, struct trackDb *tdb, double priority, double multiplier)
/* Walk the trackDb hierarchy looking for visible leaf tracks. */
{
struct trackDb *subTdb;
char buffer[4096];
if (tdb->subtracks)
{
for(subTdb = tdb->subtracks; subTdb; subTdb = subTdb->next)
checkForVisible(cart, grp, list, subTdb, priority + tdb->priority * multiplier, multiplier / 100.0);
}
else
{
boolean isVisible = FALSE;
if (tdb->parent == NULL)
{
char *cartVis = cartOptionalString(cart, tdb->track);
if (cartVis == NULL)
isVisible = tdb->visibility != tvHide;
else
isVisible = differentString(cartVis, "hide");
}
else if (isParentVisible(cart, tdb) && isSubtrackVisible(cart, tdb))
isVisible = TRUE;
if (isVisible)
{
struct trackDbRef *tdbRef;
AllocVar(tdbRef);
tdbRef->tdb = tdb;
tdbRef->grp = grp;
slAddHead(list, tdbRef);
safef(buffer, sizeof buffer, "%s_imgOrd", tdb->track);
tdbRef->order = cartUsualInt(cart, buffer, 0);
tdbRef->priority = priority + multiplier * tdb->priority;
}
}
}
static int tdbRefCompare (const void *va, const void *vb)
// Compare to sort on imgTrack->order.
{
const struct trackDbRef *a = *((struct trackDbRef **)va);
const struct trackDbRef *b = *((struct trackDbRef **)vb);
int dif = a->order - b->order;
if (dif == 0)
{
double ddif = a->priority - b->priority ;
if (ddif < 0)
dif = -1;
else if (ddif > 0)
dif = 1;
}
if (dif == 0)
dif = strcasecmp(a->tdb->shortLabel, b->tdb->shortLabel);
return dif;
}
static void addVisibleTracks(struct hash *groupHash, struct dyString *rootChildren, struct cart *cart, struct trackDb *trackList)
// add the visible tracks table rows.
{
struct trackDb *tdb;
struct trackDbRef *tdbRefList = NULL, *tdbRef;
for(tdb = trackList; tdb; tdb = tdb->next)
{
struct grp *grp = hashMustFindVal(groupHash, tdb->grp);
double priority = grp->priority + tdb->priority/100.0;
checkForVisible(cart, grp, &tdbRefList, tdb, priority, 1.0/100.0);
}
slSort(&tdbRefList, tdbRefCompare);
if (!isEmpty(rootChildren->string))
dyStringPrintf(rootChildren, ",");
dyStringPrintf(rootChildren, "{icon:'../images/folderC.png',id:'visible', text:'Visible Tracks', parent:'#', li_attr:{title:'%s'} ", FOLDER_TITLE);
if (tdbRefList != NULL)
dyStringPrintf(rootChildren, ",children:true");
dyStringPrintf(rootChildren, "}");
jsInlineF("trackData['visible'] = [");
for(tdbRef = tdbRefList; tdbRef; tdbRef = tdbRef->next)
{
trackToClient("visible", tdbRef->tdb, FALSE);
if (tdbRef->next != NULL)
jsInlineF(",");
}
jsInlineF("];");
}
void subTracksToClient(char *arrayName, struct trackDb *parentTdb, boolean user)
{
if (parentTdb->subtracks == NULL)
return;
jsInlineF("%s['%s'] = [", arrayName, trackHubSkipHubName(parentTdb->track));
boolean first = TRUE;
struct trackDb *tdb;
for(tdb = parentTdb->subtracks; tdb; tdb = tdb->next)
{
if (!first)
jsInlineF(",");
trackToClient(trackHubSkipHubName(parentTdb->track), tdb, user);
first = FALSE;
}
jsInlineF("];");
for(tdb = parentTdb->subtracks; tdb; tdb = tdb->next)
subTracksToClient(arrayName,tdb, user);
}
void addSubtrackNames(struct dyString *dy, struct trackDb *parentTdb)
{
if (parentTdb->subtracks == NULL)
return;
struct trackDb *tdb;
for(tdb = parentTdb->subtracks; tdb; tdb = tdb->next)
{
dyStringPrintf(dy, "collectionNames['%s']=1;", trackHubSkipHubName(tdb->track));
addSubtrackNames(dy, tdb);
}
}
static void doTable(struct cart *cart, char *db, struct grp *groupList, struct trackDb *trackList)
// output the tree table
{
char *hubName = hubNameFromUrl(getHubName(cart, db));
struct grp *curGroup;
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 *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(",");
}
trackToClient("#", tdb, TRUE);
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))
{
subTracksToClient("collectionData", tdb, TRUE);
addSubtrackNames(dyNames, tdb);
}
}
}
else
jsInlineF("collectionData['#'] = [];");
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, FOLDER_TITLE);
struct trackDb *tdb;
jsInlineF("trackData['%s'] = [", curGroup->name);
boolean first = TRUE;
for(tdb = trackList; tdb; tdb = tdb->next)
{
if ( sameString(tdb->grp, curGroup->name))
{
if (!first)
jsInlineF(",");
trackToClient(curGroup->name, tdb, FALSE);
first = FALSE;
}
}
jsInlineF("];");
for(tdb = trackList; tdb; tdb = tdb->next)
{
if ( sameString(tdb->grp, curGroup->name))
subTracksToClient("trackData", tdb, FALSE);
}
}
jsInlineF("trackData['#'] = [%s];", rootChildren->string);
jsInlineF("var collectionTitle='%s';\n", COLLECTION_TITLE);
jsInlineF("var folderTitle='%s';\n", FOLDER_TITLE);
jsInlineF("var trackTitle='%s';\n", TRACK_TITLE);
jsInlineF("hgCollection.init();\n");
}
static void printHelp()
// print out the help page
{
puts(
"
\n"
"