3ec039397b40eaa784d02994512b9bc5d69ae1c8 braney Sun Jun 11 15:50:34 2017 -0700 ongoing work on hgComposite diff --git src/hg/hgComposite/hgComposite.c src/hg/hgComposite/hgComposite.c index 32658c4..494f981 100644 --- src/hg/hgComposite/hgComposite.c +++ src/hg/hgComposite/hgComposite.c @@ -1,927 +1,1240 @@ /* hgComposite --- build a composite */ /* Copyright (C) 2017 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include "common.h" #include "linefile.h" #include "hash.h" #include "options.h" #include "jksql.h" #include "htmshell.h" #include "web.h" #include "cheapcgi.h" #include "cart.h" #include "cartTrackDb.h" #include "genbank.h" #include "hgConfig.h" #include "hgHgvs.h" #include "hui.h" #include "grp.h" #include "hCommon.h" #include "hgFind.h" #include "hPrint.h" #include "jsHelper.h" #include "memalloc.h" #include "textOut.h" #include "trackHub.h" #include "hubConnect.h" #include "twoBit.h" #include "gpFx.h" #include "bigGenePred.h" #include "udc.h" #include "knetUdc.h" #include "cartTrackDb.h" #include "trashDir.h" #include "customComposite.h" #define hgCompEditPrefix "hgCompositeEdit_" #define hgsAddTrack hgCompEditPrefix "addTrack" +#define hgsAddMathTrack hgCompEditPrefix "addMathTrack" +#define hgsDeleteMathTrack hgCompEditPrefix "deleteMathTrack" +#define hgsDeleteTrack hgCompEditPrefix "deleteTrack" #define hgsAddVisTrack hgCompEditPrefix "addVisTrack" #define hgsChangeGroup hgCompEditPrefix "changeGroup" #define hgsCurrentGroup hgCompEditPrefix "currentGroup" #define hgsCurrentComposite hgCompEditPrefix "currentComposite" +#define hgsMakeMathTrack hgCompEditPrefix "makeMathTrack" +#define hgsCurrentMathTrack hgCompEditPrefix "currentMathTrack" #define hgsNewCompositeName hgCompEditPrefix "newCompositeName" +#define hgsNewMathTrackShortLabel hgCompEditPrefix "newMathTrackShortLabel" +#define hgsNewMathTrackLongLabel hgCompEditPrefix "newMathTrackLongLabel" #define hgsNewCompositeShortLabel hgCompEditPrefix "newCompositeShortLabel" #define hgsNewCompositeLongLabel hgCompEditPrefix "newCompositeLongLabel" //#define hgCompositePrefix "hgComposite_" #define hgDoNewComposite hgCompEditPrefix "doNewComposite" struct track { struct track *next; char *name; char *shortLabel; char *longLabel; +void *reserved; }; struct composite { struct composite *next; char *name; char *shortLabel; char *longLabel; struct track *trackList; }; +struct mathTrack +{ +struct mathTrack *next; +char *name; +char *shortLabel; +char *longLabel; +struct track *trackList; +}; + /* Global Variables */ struct cart *cart; /* CGI and other variables */ struct hash *oldVars = NULL; /* The cart before new cgi stuff added. */ char *genome = NULL; /* Name of genome - mouse, human, etc. */ char *database = NULL; /* Current genome database - hg17, mm5, etc. */ struct grp *fullGroupList = NULL; /* List of all groups. */ // Null terminated list of CGI Variables we don't want to save permanently: -char *excludeVars[] = {"Submit", "submit", "hgva_startQuery", hgsAddTrack, hgsNewCompositeName, hgsNewCompositeShortLabel, hgsNewCompositeLongLabel, hgsChangeGroup, hgsAddVisTrack, NULL}; +char *excludeVars[] = {"Submit", "submit", "hgva_startQuery", hgsAddTrack, hgsNewCompositeName, hgsNewCompositeShortLabel, hgsNewCompositeLongLabel, hgsNewMathTrackShortLabel, hgsNewMathTrackLongLabel, hgsChangeGroup, hgsAddVisTrack, hgsAddMathTrack, hgsDeleteMathTrack, "createNewComposite", "deleteComposite", "makeMathWig", NULL}; + +static struct trackDb *findTrack(char *name, struct trackDb *fullTrackList) +{ +struct trackDb *tdb; +for (tdb = fullTrackList; tdb != NULL; tdb = tdb->next) + { + if (sameString(name, tdb->track)) + return tdb; + } +errAbort("cannot find track"); +return NULL; +} void nbSpaces(int count) /* Print some non-breaking spaces. */ { int i; for (i=0; i<count; ++i) printf(" "); } void addSomeCss() /*#*** This should go in a .css file of course. */ { printf("<style>\n" "div.sectionLite { border-width: 1px; border-color: #"HG_COL_BORDER"; border-style: solid;" " background-color: #FFFFFF; padding-left: 10px; padding-right: 10px; " " padding-top: 8px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px }\n" ".sectionLiteHeader { font-weight: bold; font-size:larger; color:#000000;" " text-align:left; vertical-align:bottom; white-space:nowrap; }\n" "div.sectionLiteHeader.noReorderRemove { padding-bottom:5px; }\n" "div.sourceFilter { padding-top: 5px; padding-bottom: 5px }\n" "</style>\n"); } INLINE void startCollapsibleSection(char *sectionSuffix, char *title, boolean onByDefault) // Wrap shared args to jsBeginCollapsibleSectionFontSize { jsBeginCollapsibleSectionFontSize(cart, "hgva", sectionSuffix, title, onByDefault, "1.1em"); } INLINE void startSmallCollapsibleSection(char *sectionSuffix, char *title, boolean onByDefault) // Wrap shared args to jsBeginCollapsibleSectionFontSize { jsBeginCollapsibleSectionFontSize(cart, "hgva", sectionSuffix, title, onByDefault, "0.9em"); } #define endCollapsibleSection jsEndCollapsibleSection static struct dyString *onChangeStart() /* Start up a javascript onChange command */ { struct dyString *dy = jsOnChangeStart(); return dy; } static char *onChangeClade() /* Return javascript executed when they change clade. */ { struct dyString *dy = onChangeStart(); jsDropDownCarryOver(dy, "clade"); dyStringAppend(dy, " document.hiddenForm.org.value=0;"); dyStringAppend(dy, " document.hiddenForm.db.value=0;"); return jsOnChangeEnd(&dy); } static char *onChangeOrg() /* Return javascript executed when they change organism. */ { struct dyString *dy = onChangeStart(); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, "org"); dyStringAppend(dy, " document.hiddenForm.db.value=0;"); return jsOnChangeEnd(&dy); } static char *onChangeDb() /* Return javascript executed when they change database. */ { struct dyString *dy = onChangeStart(); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, "db"); return jsOnChangeEnd(&dy); } INLINE void printOption(char *val, char *selectedVal, char *label) /* For rolling our own select without having to build conditional arrays/lists. */ { printf("<OPTION VALUE='%s'%s>%s\n", val, (sameString(selectedVal, val) ? " SELECTED" : ""), label); } -static struct composite *getCompositeList(char *db, char *hubName, struct hash *nameHash) +static struct composite *getCompositeList(char *db, char *hubName, struct hash *nameHash, struct trackDb *wigTracks) { struct composite *compositeList = NULL; FILE *f; if ((hubName != NULL) && ((f = fopen(hubName, "r")) != NULL)) { fclose(f); // read hub to find names of composites and add them to compositeList struct trackDb *tdbList = trackDbFromRa(hubName, NULL); struct trackDb *tdb, *tdbNext; struct composite *composite = NULL; struct track *track = NULL; for(tdb = tdbList; tdb; tdb = tdbNext) { hashAdd(nameHash, tdb->track, tdb); tdbNext = tdb->next; trackDbFieldsFromSettings(tdb); if (trackDbSetting(tdb, "compositeTrack")) { AllocVar(composite); slAddHead(&compositeList, composite); composite->name = tdb->track; composite->shortLabel = tdb->shortLabel; composite->longLabel = tdb->longLabel; } else { if (composite == NULL) errAbort("track not in composite"); AllocVar(track); track->name = tdb->track; track->shortLabel = tdb->shortLabel; track->longLabel = tdb->longLabel; slAddHead(&composite->trackList, track); + if (sameString(tdb->type, "mathWig")) + { + struct mathTrack *mathTrack = (struct mathTrack *)track; + char *equation = hashMustFindVal(tdb->settingsHash, "trackNames"); + char *words[100]; + int count = chopByWhite(equation, words, sizeof(words)/sizeof(char *)); + struct track *subTrack; + int ii; + for (ii=0; ii < count; ii++) + { + AllocVar(subTrack); + slAddHead(&mathTrack->trackList, subTrack); + subTrack->name = cloneString(words[ii]); + struct trackDb *tdb = findTrack(subTrack->name, wigTracks); + subTrack->shortLabel = tdb->shortLabel; + subTrack->longLabel = tdb->longLabel; + } + } } } } return compositeList; } static char *getSqlBigWig(struct sqlConnection *conn, char *db, struct trackDb *tdb) { char buffer[4096]; safef(buffer, sizeof buffer, "NOSQLINJ select fileName from %s", tdb->table); return sqlQuickString(conn, buffer); } static int snakePalette2[] = { 0x1f77b4, 0xaec7e8, 0xff7f0e, 0xffbb78, 0x2ca02c, 0x98df8a, 0xd62728, 0xff9896, 0x9467bd, 0xc5b0d5, 0x8c564b, 0xc49c94, 0xe377c2, 0xf7b6d2, 0x7f7f7f, 0xc7c7c7, 0xbcbd22, 0xdbdb8d, 0x17becf, 0x9edae5 }; -void outTdb(struct sqlConnection *conn, char *db, FILE *f, char *name, struct trackDb *tdb, char *parent, unsigned int color) +char *getUrl(struct sqlConnection *conn, char *db, struct trackDb *wigTracks, struct track *track) +{ +struct trackDb *tdb = findTrack(track->name, wigTracks); +char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl"); +if (bigDataUrl == NULL) + { + if (startsWith("bigWig", tdb->type)) + bigDataUrl = getSqlBigWig(conn, db, tdb); + } +return bigDataUrl; +} + +void outTdb(struct sqlConnection *conn, char *db, FILE *f, char *name, struct trackDb *tdb, char *parent, unsigned int color, struct track *track, struct trackDb *wigTracks) { char *dataUrl = NULL; char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl"); if (bigDataUrl == NULL) { if (startsWith("bigWig", tdb->type)) dataUrl = getSqlBigWig(conn, db, tdb); } struct hashCookie cookie = hashFirst(tdb->settingsHash); struct hashEl *hel; fprintf(f, "\ttrack %s\n", name); while ((hel = hashNext(&cookie)) != NULL) { - if (differentString(hel->name, "parent") && differentString(hel->name, "polished")&& differentString(hel->name, "color")&& differentString(hel->name, "track")) + if (sameString(hel->name, "mathDataUrl")) + { + fprintf(f, "\ttrackNames "); + struct mathTrack *mt = (struct mathTrack *)track; + struct track *tr = mt->trackList; + for(; tr; tr = tr->next) + { + fprintf(f, "%s ", tr->name); + } + fprintf(f, "\n"); + + fprintf(f, "\tmathDataUrl "); + tr = mt->trackList; + for(; tr; tr = tr->next) + { + fprintf(f, "%s ", getUrl(conn, db, wigTracks, tr)); + } + fprintf(f, "\n"); + } + else if (differentString(hel->name, "parent") && differentString(hel->name, "polished")&& differentString(hel->name, "color")&& differentString(hel->name, "track")&& differentString(hel->name, "trackNames")) fprintf(f, "\t%s %s\n", hel->name, (char *)hel->val); } if (bigDataUrl == NULL) { if (dataUrl != NULL) fprintf(f, "\tbigDataUrl %s\n", dataUrl); } fprintf(f, "\tparent %s\n",parent); fprintf(f, "\tcolor %d,%d,%d\n", (color >> 16) & 0xff,(color >> 8) & 0xff,color & 0xff); fprintf(f, "\n"); } static void outComposite(FILE *f, struct composite *composite) { char *parent = composite->name; char *shortLabel = composite->shortLabel; char *longLabel = composite->longLabel; fprintf(f,"track %s\n\ shortLabel %s\n\ compositeTrack on\n\ aggregate none\n\ longLabel %s\n\ %s on\n\ type wig \n\ visibility full\n\n", parent, shortLabel, longLabel, CUSTOM_COMPOSITE_SETTING); } -static struct trackDb *findTrack(char *name, struct trackDb *fullTrackList) -{ -struct trackDb *tdb; -for (tdb = fullTrackList; tdb != NULL; tdb = tdb->next) - { - if (sameString(name, tdb->track)) - return tdb; - } -errAbort("cannot find track"); -return NULL; -} - static void outHubHeader(FILE *f, char *db, char *hubName) { char *hubFile = strrchr(hubName, '/') + 1; fprintf(f,"hub hub1\n\ shortLabel User Composite\n\ longLabel User Composite\n\ genomesFile %s\n\ email braney@soe.ucsc.edu\n\ descriptionUrl hub.html\n\n", hubFile); fprintf(f,"genome %s\n\ trackDb %s\n\n", db, hubFile); } static char *getHubName(char *db) { struct tempName hubTn; char buffer[4096]; safef(buffer, sizeof buffer, "%s-%s", customCompositeCartName, db); char *hubName = cartOptionalString(cart, buffer); if (hubName == NULL) { trashDirDateFile(&hubTn, "hgComposite", "hub", ".txt"); hubName = cloneString(hubTn.forCgi); cartSetString(cart, buffer, hubName); FILE *f = mustOpen(hubName, "a"); outHubHeader(f, db, hubName); fclose(f); cartSetString(cart, "hubUrl", hubName); cartSetString(cart, hgHubConnectRemakeTrackHub, hubName); } return hubName; } -static void outputCompositeHub(char *db, char *hubName, struct composite *compositeList, struct hash *nameHash) +static void outputCompositeHub(char *db, char *hubName, struct composite *compositeList, struct hash *nameHash, struct trackDb *wigTracks) { chmod(hubName, 0666); FILE *f = mustOpen(hubName, "w"); outHubHeader(f, db, hubName); int useColor = 0; struct composite *composite; struct sqlConnection *conn = hAllocConn(db); for(composite = compositeList; composite; composite = composite->next) { outComposite(f, composite); struct trackDb *tdb; struct track *track; for (track = composite->trackList; track; track = track->next) { tdb = hashMustFindVal(nameHash, track->name); - outTdb(conn, db, f, track->name,tdb, composite->name, snakePalette2[useColor]); + outTdb(conn, db, f, track->name,tdb, composite->name, snakePalette2[useColor], track, wigTracks); useColor++; if (useColor == (sizeof snakePalette2 / sizeof(int))) useColor = 0; } } fclose(f); hFreeConn(&conn); } void topLabelSpansStart(char *label) { printf("<span style='display: inline-block; padding-right: 5px;'>" "<span style='display: block;'>%s</span>\n" "<span style='display: block; padding-bottom: 5px;'>\n", label); } void topLabelSpansEnd() { printf("</span></span>"); } void printCtAndHubButtons() /* Print a div with buttons for hgCustom and hgHubConnect */ { boolean hasCustomTracks = customTracksExist(cart, NULL); puts("<div style='padding-top: 5px; padding-bottom: 5px'>"); hOnClickButton("prtCtHub_CtBut", "document.customTrackForm.submit(); return false;", hasCustomTracks ? CT_MANAGE_BUTTON_LABEL : CT_ADD_BUTTON_LABEL); printf(" "); if (hubConnectTableExists()) hOnClickButton("prtCtHub_TrkHub", "document.trackHubForm.submit(); return false;", "track hubs"); nbSpaces(3); printf("To reset <B>all</B> user cart settings (including custom tracks), \n" "<A HREF=\"cartReset?destination=%s\">click here</A>.\n", cgiScriptName()); puts("</div>"); } void hgGatewayCladeGenomeDb() /* Make a row of labels and row of buttons like hgGateway, but not using tables. */ { boolean gotClade = hGotClade(); if (gotClade) { topLabelSpansStart("clade"); printCladeListHtml(genome, "change", onChangeClade()); topLabelSpansEnd(); } topLabelSpansStart("genome"); if (gotClade) printGenomeListForCladeHtml(database, "change", onChangeOrg()); else printGenomeListHtml(database, "change", onChangeOrg()); topLabelSpansEnd(); topLabelSpansStart("assembly"); printAssemblyListHtml(database, "change", onChangeDb()); topLabelSpansEnd(); puts("<BR>"); topLabelSpansEnd(); topLabelSpansStart(""); printf("</span>\n"); topLabelSpansEnd(); puts("<BR>"); } void printAssemblySection() /* Print assembly-selection stuff. * Redrawing the whole page when the assembly changes seems fine to me. */ { //#*** ---------- More copied verbatim, from hgTables/mainPage.c: ----------- /* Hidden form - for benefit of javascript. */ { static char *saveVars[] = { "clade", "org", "db", }; jsCreateHiddenForm(cart, cgiScriptName(), saveVars, ArraySize(saveVars)); } -hPrintf("<FORM ACTION='%s' NAME='changeGroupForm'>", cgiScriptName()); -cartSaveSession(cart); -cgiMakeHiddenVar(hgsCurrentGroup, ""); -hPrintf("</FORM>\n"); - -hPrintf("<FORM ACTION='%s' NAME='changeCompositeForm'>", cgiScriptName()); -cartSaveSession(cart); -cgiMakeHiddenVar(hgsCurrentComposite, ""); -hPrintf("</FORM>\n"); - -hPrintf("<FORM ACTION='%s' NAME='makeNewCompositeForm'>", cgiScriptName()); -cartSaveSession(cart); -cgiMakeHiddenVar(hgsNewCompositeName, ""); -cgiMakeHiddenVar(hgsNewCompositeShortLabel, ""); -cgiMakeHiddenVar(hgsNewCompositeLongLabel, ""); -hPrintf("</FORM>\n"); - -hPrintf("<FORM ACTION='%s' NAME='addVisTrackForm'>", cgiScriptName()); -cartSaveSession(cart); -cgiMakeHiddenVar(hgsAddVisTrack, ""); -hPrintf("</FORM>\n"); - -hPrintf("<FORM ACTION='%s' NAME='addTrackForm'>", cgiScriptName()); -cartSaveSession(cart); -cgiMakeHiddenVar(hgsAddTrack, ""); -hPrintf("</FORM>\n"); - -/* Hidden form for jumping to custom tracks CGI. */ -hPrintf("<FORM ACTION='%s' NAME='customTrackForm'>", hgCustomName()); -cartSaveSession(cart); -hPrintf("</FORM>\n"); - -/* Hidden form for jumping to track hub manager CGI. */ -hPrintf("<FORM ACTION='%s' NAME='trackHubForm'>", hgHubConnectName()); -cartSaveSession(cart); -hPrintf("</FORM>\n"); - -printf("<FORM ACTION=\"%s\" NAME=\"mainForm\" ID=\"mainForm\" METHOD=%s>\n", - cgiScriptName(), cartUsualString(cart, "formMethod", "GET")); -cartSaveSession(cart); //#*** ------------------ end verbatim --------------- printf("<div class='sectionLiteHeader noReorderRemove'>" "Select Genome Assembly</div>\n"); /* Print clade, genome and assembly line. */ hgGatewayCladeGenomeDb(); } static void printCompositeList(struct composite *compositeList, struct composite *currentComposite) { -if (compositeList == NULL) - return; +if (compositeList != NULL) + { printf("<div class='sectionLiteHeader noReorderRemove'>" "My Composites</div>\n"); int count = slCount(compositeList); char *labels[count]; char *names[count]; count = 0; for(; compositeList; compositeList = compositeList->next) { labels[count] = compositeList->shortLabel; names[count] = compositeList->name; count++; } + printf("Current composite: "); cgiMakeDropListFull("compositeList", labels, names, count, currentComposite->name, "change", "var e = document.getElementById('compositeList'); \ var strUser = e.options[e.selectedIndex].value; \ document.changeCompositeForm.elements['"hgsCurrentComposite"'].value = strUser; \ document.changeCompositeForm.submit();"); //document.addTrackForm.elements['hgComp_track'] = strUser;"); + hOnClickButton("deleteComposite", "document.deleteCompositeForm.submit(); return false;", "Delete Composite"); + } +hOnClickButton("new2Composite", "document.makeNewCompositeForm.submit(); return false;", "New Composite"); + } -static void makeAddComposite() +static void printCompositeLabels(struct composite *composite) { -printf("<BR>"); -printf("<BR>"); -printf("<H3>Make New Composite</H3>"); -printf("name "); -cgiMakeTextVar(hgsNewCompositeName, "", 29); +if (composite == NULL) + return; + printf("<BR>short label "); -cgiMakeTextVar(hgsNewCompositeShortLabel, "", 29); +cgiMakeTextVar(hgsNewCompositeShortLabel, composite->shortLabel, 29); printf("<BR>long label "); -cgiMakeTextVar(hgsNewCompositeLongLabel, "", 29); +cgiMakeTextVar(hgsNewCompositeLongLabel, composite->longLabel, 29); printf("<BR>"); hOnClickButton("selVar_MakeNewComposite", - "var e = document.getElementById('"hgsNewCompositeName"'); \ - document.makeNewCompositeForm.elements['"hgsNewCompositeName"'].value = e.value; \ + "var e = document.getElementById('"hgsNewCompositeLongLabel"'); \ + var strUser = e.value; \ + document.editCompositeForm.elements['"hgsNewCompositeLongLabel"'].value = strUser; \ var e = document.getElementById('"hgsNewCompositeShortLabel"'); \ - document.makeNewCompositeForm.elements['"hgsNewCompositeShortLabel"'].value = e.value; \ - var e = document.getElementById('"hgsNewCompositeLongLabel"'); \ - document.makeNewCompositeForm.elements['"hgsNewCompositeLongLabel"'].value = e.value; \ -document.makeNewCompositeForm.submit(); return false;", "submit"); + var strUser = e.value; \ + document.editCompositeForm.elements['"hgsNewCompositeShortLabel"'].value = strUser; \ +document.editCompositeForm.submit();" , "make changes"); printf("<BR>"); } -static void printTrackList(struct composite *composite) +static boolean printMakeMath(struct mathTrack *currentMathTrack) { -printf("<div class='sectionLiteHeader noReorderRemove'>" - "Tracks in Composite</div>\n"); +if (currentMathTrack == NULL) + { + hOnClickButton("makeMathWig", "document.makeMathWigForm.submit(); return FLASE;", "Add Math Track to Composite"); + + + return FALSE; + } + +printf("<BR>short label "); +cgiMakeTextVar(hgsNewMathTrackShortLabel, currentMathTrack->shortLabel, 29); +printf("<BR>long label "); +cgiMakeTextVar(hgsNewMathTrackLongLabel, currentMathTrack->longLabel, 29); +struct track *track; +hOnClickButton("selVar_newMathLabels", + "var e = document.getElementById('"hgsNewMathTrackLongLabel"'); \ + var strUser = e.value; \ + document.editMathTrackForm.elements['"hgsNewMathTrackLongLabel"'].value = strUser; \ + var e = document.getElementById('"hgsNewMathTrackShortLabel"'); \ + var strUser = e.value; \ + document.editMathTrackForm.elements['"hgsNewMathTrackShortLabel"'].value = strUser; \ +document.editMathTrackForm.submit();" , "make changes"); printf("<BR>"); -printf("<div style=\"max-width:1024px\">"); printf("<table id=\"sessionTable\" class=\"sessionTable stripe hover row-border compact\" borderwidth=0>\n"); printf("<thead><tr>"); -printf("<TH><TD><B>Name</B></TD></TH>"); +printf("<TD><B>Name</B></TD><TD>Color</TD><TD>Edit</TD><TD>Delete</TD>"); +printf("</tr></thead><tbody>"); +if (currentMathTrack) + for(track = currentMathTrack->trackList; track; track = track->next) + { + printf("<TR>\n"); + printf("<TD>%s</TD>",track->shortLabel); + printf("<TD>COLORSELECTOR</TD>"); + printf("<TD>"); + hOnClickButton("selVar_AddAllVis", "document.addVisTrackForm.submit(); return false;", "Edit Track"); + printf("</TD>"); + printf("<TD>"); + char javaScript[4096]; + safef(javaScript, sizeof javaScript, + "document.deleteMathTrackForm.elements['"hgsDeleteMathTrack"'].value = '%s'; " + "document.deleteMathTrackForm.submit(); return false;", + track->name); + char buttonName[1024]; + safef(buttonName, sizeof buttonName, "delMathTrack%s", track->name); + hOnClickButton(buttonName, javaScript, "Delete Track"); + printf("</TD>"); + printf("</TR>\n"); + } +printf("</tbody></table>"); +return TRUE; +} + + +static void printTrackList(struct composite *composite) +{ +printf("<table id=\"sessionTable\" class=\"sessionTable stripe hover row-border compact\" borderwidth=0>\n"); +printf("<thead><tr>"); +printf("<TD><B>Name</B></TD><TD>Color</TD><TD>Edit</TD><TD>Delete</TD>"); printf("</tr></thead><tbody>"); struct track *track; if (composite) for(track = composite->trackList; track; track = track->next) { - printf("<TR><TD>%s</TD></TR>\n",track->shortLabel); + printf("<TR>\n"); + printf("<TD>%s</TD>",track->shortLabel); + printf("<TD>COLORSELECTOR</TD>"); +printf("<TD>"); +hOnClickButton("selVar_AddAllVis", "document.addVisTrackForm.submit(); return false;", "Edit Track"); +printf("</TD>"); +printf("<TD>"); + char javaScript[4096]; + safef(javaScript, sizeof javaScript, + "document.deleteTrackForm.elements['"hgsDeleteTrack"'].value = '%s'; " + "document.deleteTrackForm.submit(); return false;", + track->name); + char buttonName[1024]; + safef(buttonName, sizeof buttonName, "delTrack%s", track->name); + hOnClickButton(buttonName, javaScript, "Delete Track"); +printf("</TD>"); + printf("</TR>\n"); } -//printf("<TR><TD>track1</TD></TR>"); -//printf("<TR><TD>track2</TD></TR>"); printf("</table>"); } static boolean trackCanBeAdded(struct trackDb *tdb) { return (tdb->subtracks == NULL) && !startsWith("wigMaf",tdb->type) && (startsWith("wig",tdb->type) || startsWith("bigWig",tdb->type)) ; } -static void availableTracks(char *db, struct grp *groupList, struct trackDb *fullTrackList) +static void availableTracks(char *db, struct grp *groupList, struct trackDb *fullTrackList, char *formName, char *varName) { printf("<H4>Add tracks from %s</H4>", db); char *curGroupName = cartOptionalString(cart, hgsCurrentGroup); printf("<BR>groups: "); char **labels, **names; int count = slCount(groupList); AllocArray(labels, count); AllocArray(names, count); count = 0; struct grp *grp; for(grp = groupList; grp; grp = grp->next) { labels[count] = grp->label; names[count] = grp->name; count++; } -cgiMakeDropListFull("availGroups", labels, names, count, - curGroupName, - "change", - "var e = document.getElementById('availGroups'); \ +char buffer[1024]; +safef(buffer, sizeof buffer, "availGroups%s", formName); +char javaScript[4096]; +safef(javaScript, sizeof javaScript, + "var e = document.getElementById('availGroups%s'); \ var strUser = e.options[e.selectedIndex].value; \ document.changeGroupForm.elements['"hgsCurrentGroup"'].value = strUser; \ - document.changeGroupForm.submit();"); + document.changeGroupForm.submit();", formName); +cgiMakeDropListFull(buffer, labels, names, count, + curGroupName, + "change", javaScript); struct grp *curGroup; if (curGroupName == NULL) curGroup = groupList; else { for(curGroup = groupList; curGroup; curGroup = curGroup->next) { if (sameString(curGroupName, curGroup->name)) break; } if (curGroup == NULL) errAbort("cannot find current group"); } struct trackDb *tdb; count = 0; for(tdb = fullTrackList; tdb; tdb = tdb->next) { if (sameString(tdb->grp, curGroup->name)) count++; } -//char **labels, **names; AllocArray(labels, count); AllocArray(names, count); count = 0; for(tdb = fullTrackList; tdb; tdb = tdb->next) { if (sameString(tdb->grp, curGroup->name)) { labels[count] = tdb->shortLabel; names[count] = tdb->track; count++; } } printf("track:"); -cgiMakeDropListFull("availTracks", labels, names, count, +safef(buffer, sizeof buffer, "availTracks%s", formName); +cgiMakeDropListFull(buffer, labels, names, count, *names, - "change", - "var e = document.getElementById('availTracks'); \ - var strUser = e.options[e.selectedIndex].value; \ - document.addTrackForm.elements['"hgsAddTrack"'].value = strUser;"); - //document.addTrackForm.elements['hgComp_track'] = strUser;"); -hOnClickButton("addTrack", - "var e = document.getElementById('availTracks'); \ + "change", ""); +safef(javaScript, sizeof javaScript, + "var e = document.getElementById('availTracks%s'); \ var strUser = e.options[e.selectedIndex].value; \ - document.addTrackForm.elements['"hgsAddTrack"'].value = strUser; \ - document.addTrackForm.submit();" -, "add track"); + document.%s.elements['%s'].value = strUser; \ + document.%s.submit();", formName, formName, varName, formName); +hOnClickButton(formName, javaScript, "add track"); printf("<BR>"); printf("<BR>"); printf("<BR>"); hOnClickButton("selVar_AddAllVis", "document.addVisTrackForm.submit(); return false;", "Add All Visibile Wiggles"); } -void doMainPage(char *db, struct grp *groupList, struct trackDb *fullTrackList, struct composite *currentComposite, struct composite *compositeList) +void doMainPage(char *db, struct grp *groupList, struct trackDb *fullTrackList, struct composite *currentComposite, struct composite *compositeList, struct mathTrack *currentMathTrack) /* Print out initial HTML of control page. */ { -//struct composite *currentComposite = compositeList; jsInit(); webIncludeResourceFile("jquery-ui.css"); webIncludeResourceFile("ui.dropdownchecklist.css"); -boolean alreadyAgreed = cartUsualBoolean(cart, "hgva_agreedToDisclaimer", FALSE); -jsInlineF( - "$(document).ready(function() { hgva.disclaimer.init(%s, hgva.userClickedAgree); });\n" - , alreadyAgreed ? "true" : "false"); addSomeCss(); +#ifdef NOTNOW printAssemblySection(); puts("<BR>"); printf("<div class='sectionLiteHeader noReorderRemove'>" "Add Hubs and Custom Tracks </div>\n"); printCtAndHubButtons(); +#endif -//struct hashEl *hel = cartFindPrefix(cart, hgCompEditPrefix); -//if (hel != NULL) +hPrintf("<FORM ACTION='%s' NAME='changeGroupForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsCurrentGroup, ""); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='changeCompositeForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsCurrentComposite, ""); +hPrintf("</FORM>\n"); + +if (currentComposite) { - // printf("printing EditCom\n"); - /// printEditComposite(); + hPrintf("<FORM ACTION='%s' NAME='deleteCompositeForm'>", cgiScriptName()); + cgiMakeHiddenVar("deleteComposite", currentComposite->name); + cartSaveSession(cart); + hPrintf("</FORM>\n"); } +hPrintf("<FORM ACTION='%s' NAME='makeMathWigForm'>", cgiScriptName()); +cgiMakeHiddenVar("makeMathWig", "on"); +cartSaveSession(cart); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='makeNewCompositeForm'>", cgiScriptName()); +cgiMakeHiddenVar("createNewComposite", "on"); +cartSaveSession(cart); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='editMathTrackForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsNewMathTrackShortLabel, ""); +cgiMakeHiddenVar(hgsNewMathTrackLongLabel, ""); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='editCompositeForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsNewCompositeShortLabel, ""); +cgiMakeHiddenVar(hgsNewCompositeLongLabel, ""); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='addVisTrackForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsAddVisTrack, ""); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='deleteTrackForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsDeleteTrack, ""); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='deleteMathTrackForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsDeleteMathTrack, ""); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='addMathTrackForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsAddMathTrack, ""); +hPrintf("</FORM>\n"); + +hPrintf("<FORM ACTION='%s' NAME='addTrackForm'>", cgiScriptName()); +cartSaveSession(cart); +cgiMakeHiddenVar(hgsAddTrack, ""); +hPrintf("</FORM>\n"); + +/* Hidden form for jumping to custom tracks CGI. */ +hPrintf("<FORM ACTION='%s' NAME='customTrackForm'>", hgCustomName()); +cartSaveSession(cart); +hPrintf("</FORM>\n"); + +/* Hidden form for jumping to track hub manager CGI. */ +hPrintf("<FORM ACTION='%s' NAME='trackHubForm'>", hgHubConnectName()); +cartSaveSession(cart); +hPrintf("</FORM>\n"); + +printf("<FORM ACTION=\"%s\" NAME=\"mainForm\" ID=\"mainForm\" METHOD=%s>\n", + cgiScriptName(), cartUsualString(cart, "formMethod", "GET")); +cartSaveSession(cart); + printf("</FORM>"); puts("<BR>"); puts("<BR>"); printCompositeList(compositeList, currentComposite); -makeAddComposite(); -puts("<BR>"); -printTrackList(currentComposite); puts("<BR>"); -availableTracks(db, groupList, fullTrackList); +printCompositeLabels(currentComposite); puts("<BR>"); -// Make wrapper table for collapsible sections: -//selectVariants(); -//char *geneTrack = selectGenes(); -//if (geneTrack != NULL) - { - //selectRegulatory(); - //selectAnnotations(geneTrack); - //selectFilters(); - //selectOutput(); - //submitAndDisclaimer(); - } +printf("<div id=\"tabs\">" + "<ul> <li><a href=\"#addTracksToComposite\">Add Tracks To Composite</a></li>" + "<li><a href=\"#addTracksToMathWig\">Add Tracks to Math Wig</a></li> " + "</ul> "); + +printf("<div id=\"addTracksToComposite\" class=\"hubList\"> \n"); +printTrackList(currentComposite); +availableTracks(db, groupList, fullTrackList, "addTrackForm", hgsAddTrack ); +puts("<BR>"); +printf("</div>"); +printf("<div id=\"addTracksToMathWig\" class=\"hubList\"> \n"); +if (printMakeMath(currentMathTrack)) + availableTracks(db, groupList, fullTrackList, "addMathTrackForm", hgsAddMathTrack); +puts("<BR>"); +printf("</div>"); +printf("</div>"); printf("</FORM>"); jsReloadOnBackButton(cart); webNewSection("Using the Composite Builder"); webIncludeHelpFileSubst("hgCompositeHelp", NULL, FALSE); jsIncludeFile("jquery-ui.js", NULL); jsIncludeFile("hgVarAnnogrator.js", NULL); jsIncludeFile("ui.dropdownchecklist.js", NULL); jsIncludeFile("ddcl.js", NULL); } -void doUi(char *db, struct grp *groupList, struct trackDb *fullTrackList,struct composite *currentComposite, struct composite *compositeList) +void doUi(char *db, struct grp *groupList, struct trackDb *fullTrackList,struct composite *currentComposite, struct composite *compositeList, struct mathTrack *currentMathTrack) /* Set up globals and make web page */ { cartWebStart(cart, db, "Composite Editor"); -doMainPage(database, groupList, fullTrackList, currentComposite, compositeList); +jsIncludeFile("jquery.js", NULL); +jsIncludeFile("utils.js", NULL); +jsIncludeFile("jquery-ui.js", NULL); + +webIncludeResourceFile("jquery-ui.css"); + +jsIncludeFile("ajax.js", NULL); +jsIncludeFile("hgHubConnect.js", NULL); +jsIncludeFile("jquery.cookie.js", NULL); + +doMainPage(database, groupList, fullTrackList, currentComposite, compositeList, currentMathTrack); cartWebEnd(); -/* Save variables. */ -//cartCheckout(&cart); } static void addWigs(struct hash *hash, struct trackDb **wigList, struct trackDb *list) // Add tracks that are acceptable in custom composites. { if (list == NULL) return; struct trackDb *tdb, *tdbNext; for(tdb = list; tdb; tdb = tdbNext) { tdbNext = tdb->next; addWigs(hash, wigList, tdb->subtracks); if (trackCanBeAdded(tdb)) { slAddHead(wigList, tdb); hashStore(hash, tdb->grp); } } } char *makeUnique(struct hash *nameHash, struct trackDb *tdb) // Make the name of this track unique. { -if (hashLookup(nameHash, tdb->track) == NULL) +char *skipHub = trackHubSkipHubName(tdb->track); +if (hashLookup(nameHash, skipHub) == NULL) { hashAdd(nameHash, tdb->track, tdb); - return tdb->track; + return skipHub; } unsigned count = 0; char buffer[4096]; for(;; count++) { - safef(buffer, sizeof buffer, "%s%d", tdb->track, count); + safef(buffer, sizeof buffer, "%s%d", skipHub, count); if (hashLookup(nameHash, buffer) == NULL) { hashAdd(nameHash, buffer, tdb); return cloneString(buffer); } } return NULL; } 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; } bool isSubtrackVisible(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; } bool isParentVisible( struct trackDb *tdb) // Are this track's parents visible? { if (tdb->parent == NULL) return TRUE; if (!isParentVisible(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; } +struct mathTrack *getMathTracks(struct composite *compositeList) +{ +struct mathTrack *mathTrackList = NULL; + +return mathTrackList; +} + +static char *createNewCompositeName(struct hash *nameHash) +{ +static int compositeNumber = 0; +char buffer[4096]; +for(;;) + { + safef(buffer, sizeof buffer, "userTrack%d", compositeNumber); + if (hashLookup(nameHash, buffer) == NULL) + { + hashStore(nameHash, buffer); + return cloneString(buffer); + } + compositeNumber++; + } +} + int main(int argc, char *argv[]) /* Process command line. */ { long enteredMainTime = clock1000(); if (hIsPrivateHost()) pushCarefulMemHandler(LIMIT_2or6GB); cgiSpoof(&argc, argv); htmlPushEarlyHandlers(); /* Make errors legible during initialization. */ oldVars = hashNew(10); cart = cartAndCookie(hUserCookie(), excludeVars, oldVars); /* Set up global variables. */ getDbAndGenome(cart, &database, &genome, oldVars); initGenbankTableNames(database); int timeout = cartUsualInt(cart, "udcTimeout", 300); if (udcCacheTimeout() < timeout) udcSetCacheTimeout(timeout); knetUdcInstall(); struct trackDb *fullTrackList = NULL; /* List of all tracks in database. */ struct trackDb *wigTracks = NULL; /* List of all wig tracks */ cartTrackDbInit(cart, &fullTrackList, &fullGroupList, TRUE); struct hash *groupHash = newHash(5); addWigs(groupHash, &wigTracks, fullTrackList); struct grp *grp, *grpNext, *groupList = NULL; for(grp = fullGroupList; grp; grp = grpNext) { grpNext = grp->next; if (hashLookup(groupHash, grp->name) != NULL) slAddHead(&groupList, grp); } slReverse(&groupList); -/* -struct grp *grpList; -struct trackDb *tdbList = hubCollectTracks(database, &grpList); -addWigs(&wigTracks, tdbList); -*/ - char *hubName = getHubName(database); struct hash *nameHash = newHash(5); -struct composite *compositeList = getCompositeList(database, hubName, nameHash); +struct composite *compositeList = getCompositeList(database, hubName, nameHash, wigTracks); + +char *deleteCompositeName = cgiOptionalString("deleteComposite"); +if (deleteCompositeName) + { + struct composite *composite, *prevComposite = NULL; + for (composite = compositeList; composite; prevComposite = composite, composite = composite->next) + { + if (sameString(composite->name, deleteCompositeName)) + break; + } + if (composite) + { + if (composite == compositeList) + compositeList = compositeList->next; + else + prevComposite->next = composite->next; + } + } struct composite *currentComposite = NULL; char *currentCompositeName = cartOptionalString(cart, hgsCurrentComposite); if (currentCompositeName != NULL) { for (currentComposite = compositeList; currentComposite; currentComposite = currentComposite->next) if (sameString(currentComposite->name, currentCompositeName)) break; } +if (currentCompositeName == NULL) + currentComposite = compositeList; if (currentComposite == NULL) currentComposite = compositeList; -char *newCompositeName = cartOptionalString(cart, hgsNewCompositeName); -if (newCompositeName != NULL) - { - if (isEmpty(newCompositeName)) - warn("Composite name must not be empty string"); - else +char *createNewComposite = cartOptionalString(cart, "createNewComposite"); +if (createNewComposite != NULL) { struct composite *composite; AllocVar(composite); slAddHead(&compositeList, composite); currentComposite = composite; - composite->name = cloneString(newCompositeName); - char *newCompositeShortLabel = cartOptionalString(cart, hgsNewCompositeShortLabel); - if (isEmpty(newCompositeShortLabel)) - composite->shortLabel = composite->name; - else - composite->shortLabel = cloneString(newCompositeShortLabel); - char *newCompositeLongLabel = cartOptionalString(cart, hgsNewCompositeLongLabel); - if (isEmpty(newCompositeLongLabel)) - composite->longLabel = composite->name; - else - composite->longLabel = cloneString(newCompositeLongLabel); + composite->name = createNewCompositeName(nameHash); + composite->shortLabel = cloneString("Short Label"); + composite->longLabel = cloneString("Long Label"); + } +char *newShortLabel = cgiOptionalString(hgsNewCompositeShortLabel); +if (newShortLabel != NULL) + { + if (currentComposite != NULL) + { + currentComposite->shortLabel = cloneString(newShortLabel); + currentComposite->longLabel = cloneString(cgiOptionalString(hgsNewCompositeLongLabel)); } } -if (currentCompositeName == NULL) - currentComposite = compositeList; +struct mathTrack *currentMathTrack = NULL; + +char *currentMathTrackName = cartOptionalString(cart, hgsCurrentMathTrack); +char *makeMathWig = cartOptionalString(cart, "makeMathWig"); + +if (makeMathWig != NULL) + { + AllocVar(currentMathTrack); + if (currentComposite == NULL) + errAbort("need currentComposite"); + slAddHead(¤tComposite->trackList, currentMathTrack); + currentMathTrack->name = createNewCompositeName(nameHash); + currentMathTrack->shortLabel = cloneString("MathWig Short"); + currentMathTrack->longLabel = cloneString("MathWig Long Label"); + cartSetString(cart, hgsCurrentMathTrack, currentMathTrack->name); + struct trackDb *tdb; + AllocVar(tdb); + hashAdd(nameHash, currentMathTrack->name, tdb); + tdb->track = currentMathTrack->name; + tdb->type = "mathWig"; + tdb->settingsHash = newHash(5); + hashAdd(tdb->settingsHash, "shortLabel",currentMathTrack->shortLabel); + hashAdd(tdb->settingsHash, "longLabel", currentMathTrack->longLabel); + hashAdd(tdb->settingsHash, "type", "mathWig"); + hashAdd(tdb->settingsHash, "mathDataUrl", ""); + } +else if (currentMathTrackName != NULL) + { + if (currentComposite == NULL) + errAbort("need currentComposite"); + for (currentMathTrack = (struct mathTrack *)currentComposite->trackList; currentMathTrack; currentMathTrack = currentMathTrack->next) + if (sameString(currentMathTrack->name, currentMathTrackName)) + break; + } + +newShortLabel = cgiOptionalString(hgsNewMathTrackShortLabel); +if (newShortLabel != NULL) + { + if (currentMathTrack != NULL) + { + struct trackDb *tdb = hashMustFindVal(nameHash, currentMathTrack->name); + hashReplace(tdb->settingsHash, "shortLabel",cloneString(newShortLabel)); + hashReplace(tdb->settingsHash, "longLabel", cloneString(cgiOptionalString(hgsNewMathTrackLongLabel))); + } + } char *addAllVisible = cartOptionalString(cart, hgsAddVisTrack); if (addAllVisible != NULL) { struct trackDb *tdb; for(tdb = wigTracks; tdb; tdb = tdb->next) { if (isParentVisible(tdb) && isSubtrackVisible(tdb)) { struct track *track; AllocVar(track); track->name = makeUnique(nameHash, tdb); track->shortLabel = tdb->shortLabel; track->longLabel = tdb->longLabel; slAddHead(¤tComposite->trackList, track); } } } +char *newMathTrackName = cartOptionalString(cart, hgsAddMathTrack); +if (newMathTrackName != NULL) + { + if (currentMathTrack == NULL) + warn("cannot add track without specifying a mathwig"); + else + { + struct trackDb *tdb = findTrack(newMathTrackName, wigTracks); + + struct track *track; + AllocVar(track); + track->name = makeUnique(nameHash, tdb); + track->shortLabel = tdb->shortLabel; + track->longLabel = tdb->longLabel; + slAddHead(¤tMathTrack->trackList, track); + } + } + +char *deleteTrackName = cartOptionalString(cart, hgsDeleteTrack); +if (deleteTrackName != NULL) + { + if (currentComposite == NULL) + warn("cannot delete track without specifying a composite"); + else + { + struct track *track, *prevTrack = NULL; + for(track = currentComposite->trackList; track; prevTrack = track,track = track->next) + { + if (sameString(track->name, deleteTrackName)) + break; + } + if (track != NULL) + { + if (prevTrack == NULL) + currentComposite->trackList = track->next; + else + prevTrack->next = track->next; + } + } + } + +char *deleteMathTrackName = cartOptionalString(cart, hgsDeleteMathTrack); +if (deleteMathTrackName != NULL) + { + if (currentMathTrack == NULL) + warn("cannot delete track without specifying a mathwig"); + else + { + struct track *track, *prevTrack = NULL; + for(track = currentMathTrack->trackList; track; prevTrack = track,track = track->next) + { + if (sameString(track->name, deleteMathTrackName)) + break; + } + if (track != NULL) + { + if (prevTrack == NULL) + currentMathTrack->trackList = track->next; + else + prevTrack->next = track->next; + } + } + } + char *newTrackName = cartOptionalString(cart, hgsAddTrack); if (newTrackName != NULL) { if (currentComposite == NULL) warn("cannot add track without specifying a composite"); else { struct trackDb *tdb = findTrack(newTrackName, wigTracks); struct track *track; AllocVar(track); track->name = makeUnique(nameHash, tdb); track->shortLabel = tdb->shortLabel; track->longLabel = tdb->longLabel; slAddHead(¤tComposite->trackList, track); } } if (currentComposite) cartSetString(cart, hgsCurrentComposite, currentComposite->name); -doUi(database, groupList, wigTracks, currentComposite, compositeList); +doUi(database, groupList, wigTracks, currentComposite, compositeList, currentMathTrack); -outputCompositeHub(database, hubName, compositeList, nameHash); +outputCompositeHub(database, hubName, compositeList, nameHash, wigTracks); cartCheckout(&cart); cgiExitTime("hgComposite", enteredMainTime); return 0; }