\n");
-}
-
-
struct trackHub *fetchTrackHub(struct hubEntry *hubInfo)
/* Fetch the hub structure for a public hub, trapping the error
* if the hub cannot be reached */
{
struct errCatch *errCatch = errCatchNew();
struct trackHub *hub = NULL;
if (errCatchStart(errCatch))
{
char hubName[4096];
safef(hubName, sizeof(hubName), "hub_%d", hubInfo->id);
hub = trackHubOpen(hubInfo->hubUrl, hubName);
}
errCatchEnd(errCatch);
if (errCatch->gotError)
{
fprintf(stderr, "%s\n", errCatch->message->string);
}
errCatchFree(&errCatch);
return hub;
}
-
-struct tdbOutputStructure *addOrUpdateTrackOut(char *track, struct genomeOutputStructure *genomeOut,
- struct hash *tdbHash, struct trackHub *hub)
-/* If an output structure already exists for the track within genomeOut, return that. Otherwise,
- * create one for it and add it to genomeOut. Any missing parent tracks are also added at
- * the same time.
- * tdbHash takes track names to the struct trackDb * for that track */
-{
-struct tdbOutputStructure *tdbOut = hashFindVal(genomeOut->tdbOutHash, track);
-if (tdbOut == NULL)
- {
- genomeOut->trackCount++;
- AllocVar(tdbOut);
- tdbOut->shortLabel = dyStringNew(0);
- tdbOut->metaTags = dyStringNew(0);
- tdbOut->descriptionMatch = dyStringNew(0);
- tdbOut->configUrl = dyStringNew(0);
- struct trackDb *trackInfo = (struct trackDb *) hashFindVal(tdbHash, track);
- if (trackInfo == NULL)
- {
- // Some tracks are prefixed with the hub name; try that
- char withHubName[4096];
- safef(withHubName, sizeof(withHubName), "%s_%s", hub->name, track);
- trackInfo = hashFindVal(tdbHash, withHubName);
- if (trackInfo == NULL)
- {
- warn("Error: Unable to locate info for matching track '%s'. Skipping ...\n", withHubName);
- return NULL;
- }
- }
- if (isNotEmpty(trackInfo->longLabel))
- dyStringPrintf(tdbOut->shortLabel, "%s", trackInfo->longLabel);
- else if (isNotEmpty(trackInfo->shortLabel))
- dyStringPrintf(tdbOut->shortLabel, "%s", trackInfo->shortLabel);
- else
- dyStringPrintf(tdbOut->shortLabel, "%s", trackHubSkipHubName(trackInfo->track));
-
- if (tdbIsCompositeView(trackInfo) || tdbIsCompositeChild(trackInfo))
- {
- struct trackDb *parentTdb = tdbGetComposite(trackInfo);
- dyStringPrintf(tdbOut->configUrl, "../cgi-bin/hgTrackUi?hubUrl=%s&db=%s&g=%s&hgsid=%s&%s", hub->url,
- genomeOut->genomeName, parentTdb->track, cartSessionId(cart), genomeOut->positionString);
- }
- else
- {
- dyStringPrintf(tdbOut->configUrl, "../cgi-bin/hgTrackUi?hubUrl=%s&db=%s&g=%s&hgsid=%s&%s", hub->url,
- genomeOut->genomeName, trackInfo->track, cartSessionId(cart), genomeOut->positionString);
- }
-
- if (trackInfo->parent != NULL)
- {
- struct trackDb *parent = trackInfo->parent;
- struct tdbOutputStructure *parentOut = addOrUpdateTrackOut(parent->track, genomeOut, tdbHash, hub);
- if (parentOut != NULL)
- {
- // addOrUpdateTrackOut only returns NULL if it can't find the parent here.
- // This probably means the trackDb is corrupted, which should have already
- // generated a fatal error. All the same ...
- slAddTail(&(parentOut->children), tdbOut);
- parentOut->childCount++;
- }
- else
- {
- // If we can't find the track's rightful parent, we can't report its position
- // in the track hierarchy accurately. Time to abort. A warning will already
- // have been generated by addOrUpdateTrackOut(parent) failing.
- return NULL;
- }
- }
- else
- // No parent track, so add it to the root level track list for output
- slAddTail(&(genomeOut->tracks), tdbOut);
- hashAdd(genomeOut->tdbOutHash, track, tdbOut);
- }
-return tdbOut;
-}
-
-
-void buildTdbHash(struct hash *tdbHash, struct trackDb *tdbList)
-/* Recursively add all tracks from tdbList to the hash (indexed by track),
- * along with all parents and children of those tracks */
-{
-struct trackDb *tdb = tdbList;
-while (tdb != NULL)
- {
- hashAdd(tdbHash, tdb->track, tdb);
- if (tdb->subtracks != NULL)
- buildTdbHash(tdbHash, tdb->subtracks);
- if (tdb->parent != NULL)
- {
- // supertracks might be omitted from tdbList, but are still referred to by parent links
- if (hashFindVal(tdbHash, tdb->parent->track) == NULL)
- hashAdd(tdbHash, tdb->parent->track, tdb->parent);
- }
- tdb = tdb->next;
- }
-}
-
-
char *getPositionStringForDb(struct trackHubGenome *genome)
{
char positionVar[1024];
safef(positionVar, sizeof(positionVar), "position.%s", genome->name);
char *position = cartOptionalString(cart, positionVar);
if (position == NULL)
{
struct dyString *tmp = dyStringCreate("position=");
if (genome->defaultPos != NULL)
dyStringAppend(tmp, genome->defaultPos);
else
dyStringAppend(tmp, hDefaultPos(genome->name)); // memory leak from hDefaultPos return value
position = dyStringCannibalize(&tmp);
}
return position;
@@ -1156,31 +993,31 @@
static char *tdbOutputStructureLabelToId(struct tdbOutputStructure *tdbOut)
/* Make an array name out of a tdbOutputStruct */
{
struct dyString *id = dyStringNew(0);
dyStringPrintf(id, "%s", htmlEncode(dyStringContents(tdbOut->shortLabel)));
if (tdbOut->childCount > 0)
{
dyStringPrintf(id, " (%d subtrack%s)", tdbOut->childCount,
tdbOut->childCount == 1 ? "" : "s");
}
return dyStringCannibalize(&id);
}
static void printTdbOutputStructureToDyString(struct tdbOutputStructure *tdbOut, struct dyString *dy, char *arrayName)
-/* Print a tdbOutputStructure to a dyString*/
+/* Print a tdbOutputStructure to a dyString, recursive for subtracks. */
{
dyStringPrintf(dy, "trackData['%s'] = [", arrayName);
if (tdbOut->childCount > 0)
{
struct dyString *subtrackDy = dyStringNew(0);
struct tdbOutputStructure *child = tdbOut->children;
while (child != NULL)
{
char *childId = tdbOutputStructureLabelToId(child);
dyStringPrintf(dy, "\n\t{\n\tid: '%s',\n\tparent: '%s',\n\t"
"li_attr: {nodetype:'track', configlink:'%s'},\n\ttext: \'%s ",
childId, arrayName, dyStringContents(child->configUrl), childId);
if (isNotEmpty(dyStringContents(child->metaTags)))
{
@@ -1197,49 +1034,47 @@
{
dyStringPrintf(dy, ",\n\tchildren: true");
printTdbOutputStructureToDyString(child, subtrackDy, childId);
}
dyStringPrintf(dy, "\n\t},");
child = child->next;
}
dyStringPrintf(dy, "];\n");
if (isNotEmpty(dyStringContents(subtrackDy)))
dyStringPrintf(dy, "%s", subtrackDy->string);
}
else
dyStringPrintf(dy, "];\n");
}
-
void printGenomeOutputStructureToDyString(struct genomeOutputStructure *genomeOut, struct dyString *dy, char *genomeNameId)
-/* Print a genomeOutputStructure to a dyString */
+/* Print a genomeOutputStructure to a dyString. The structure here is:
+ * trackData[genome] = [{track 1 obj}, {track2 obj}, {track3 obj}, ... ]
+ * trackData[track1] = [{search hit text}, {subtrack1 obj}, {subtrack2 obj}, ... ]
+ *
+ * if track1, track2, track3 are container tracks, then the recursive function
+ * tdbOutputStructureToDystring creates the above trackData[track1] = [{}] for
+ * each of the containers, otherwise a single child of the genome is sufficient */
{
struct tdbOutputStructure *tdbOut = NULL;
static struct dyString *tdbArrayDy = NULL; // the dyString for all of the tdb objects
static struct dyString *idString = NULL; // the special id of this track
if (tdbArrayDy == NULL)
tdbArrayDy = dyStringNew(0);
if (idString == NULL)
idString = dyStringNew(0);
-// The structure here is:
-// trackData[genome] = [{track 1 obj}, {track2 obj}, {track3 obj}, ... ]
-// trackData[track1] = [{search hit text}, {subtrack1 search hit}, {subtrack2 search hit}, ... ]
-//
-// if track1, track2, track3 are container tracks, then the recursive function
-// tdbOutputStructureToDystring creates the above trackData[track1] = [{}] for
-// each of the containers, otherwise a single child of the genome is sufficient
dyStringPrintf(dy, "trackData['%s'] = [", genomeNameId);
if (genomeOut->tracks != NULL)
{
tdbOut = genomeOut->tracks;
slReverse(&tdbOut);
while (tdbOut != NULL)
{
dyStringPrintf(idString, "%s", tdbOutputStructureLabelToId(tdbOut));
dyStringPrintf(dy, "\n\t{\n\t'id': '%s',\n\t'parent': '%s',\n\t"
"'li_attr': {'nodetype':'track', configlink: '%s'},\n\t'text': \'%s ",
idString->string, genomeNameId, dyStringContents(tdbOut->configUrl), idString->string);
if (isNotEmpty(dyStringContents(tdbOut->metaTags)))
{
dyStringPrintf(dy, " Metadata: %s",
htmlEncode(dyStringContents(tdbOut->metaTags)));
@@ -1254,35 +1089,40 @@
// above we took care of both non-heirarchical tracks and the top-level containers,
// now do container children, which also takes care of any deeper heirarchies
if (tdbOut->childCount > 0)
dyStringPrintf(dy, ",\n\t'children': true");
dyStringPrintf(dy, "\n\t},\n");
if (tdbOut->childCount > 0)
printTdbOutputStructureToDyString(tdbOut, tdbArrayDy, idString->string);
tdbOut = tdbOut->next;
dyStringClear(idString);
}
}
dyStringPrintf(dy, "];\n"); // close off genome node
dyStringPrintf(dy, "%s\n", tdbArrayDy->string);
dyStringClear(tdbArrayDy);
-dyStringClear(idString);
}
void printHubOutputStructure(struct hubOutputStructure *hubOut, struct hubEntry *hubInfo)
-/* Convert a hubOutputStructure to a jstree-readable string */
+/* Convert a hubOutputStructure to a jstree-readable string. This function forms the root
+ * node for each hub search tree, whose children are the hub description match and each individual
+ * genome node. A simplified structure is:
+ * trackData['#_hubId'] = [{id:'descriptionMatch',...},{id:'assembly1',...},...]
+ *
+ * The id's become new "trackData[id]" entries with their own arrays later if they have
+ * sub-trees (via printGenomeOutputStructureToDyString() and printTdbOutputStructureToDyString(). */
{
struct dyString *dy = dyStringNew(0);
// The leading '#' tells the javascript this is a 'root' node
dyStringPrintf(dy, "trackData['#_%d'] = [", hubInfo->id);
if (isNotEmpty(dyStringContents(hubOut->descriptionMatch)))
{
dyStringPrintf(dy, "{'id':'%d_descriptionMatchText','parent':'#_%d',"
"'state':{'opened': true},'text': 'Hub Description: "
"%s'},",
hubInfo->id, hubInfo->id, htmlEncode(dyStringContents(hubOut->descriptionMatch)));
}
struct genomeOutputStructure *genomeOut = hubOut->genomes;
struct dyString *genomeDy = dyStringNew(0);
if (genomeOut != NULL)
{