0f483165e902359c81642c1ab20aed49ea96f272
tdreszer
  Fri Dec 10 09:21:38 2010 -0800
Split compositeUiSubtracks into hgTrackUi vs hgTable versions.  Remade subtrack list using the new 'sortable' table methods.  Remade makeTrackHashWithComposites to take in/out for tdbList, enabling few rebuilds of this list.
diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 45c059e..df80277 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -42,51 +42,52 @@
 #define PM_BUTTON  "<IMG height=18 width=18 onclick=\"setCheckBoxesThatContain('%s',%s,true,'%s','','%s');\" id=\"btn_%s\" src=\"../images/%s\" alt=\"%s\">\n"
 #define DEF_BUTTON "<IMG onclick=\"setCheckBoxesThatContain('%s',true,false,'%s','','%s'); setCheckBoxesThatContain('%s',false,false,'%s','_defOff','%s');\" id=\"btn_%s\" src=\"../images/%s\" alt=\"%s\">\n"
 #define DEFAULT_BUTTON(nameOrId,anc,beg,contains) printf(DEF_BUTTON,(nameOrId),        (beg),(contains),(nameOrId),(beg),(contains),(anc),"defaults_sm.png","default")
 #define    PLUS_BUTTON(nameOrId,anc,beg,contains) printf(PM_BUTTON, (nameOrId),"true", (beg),(contains),(anc),"add_sm.gif",   "+")
 #define   MINUS_BUTTON(nameOrId,anc,beg,contains) printf(PM_BUTTON, (nameOrId),"false",(beg),(contains),(anc),"remove_sm.gif","-")
 
 #define ENCODE_DCC_DOWNLOADS "encodeDCC"
 
 //#define SUBTRACK_CFG_POPUP
 #define BAM_CFG_UI_CHANGES
 
 struct trackDb *wgEncodeDownloadDirKeeper(char *db, struct trackDb *tdb, struct hash *trackHash)
 /* Look up through self and parents, looking for someone responsible for handling
  * where the downloads are. */
 {
-if (!sameString(tdb->table, tdb->track))
+if (!sameWord(tdb->type,"downloadsOnly") && !sameString(tdb->table, tdb->track))
     {
     tdb = hashFindVal(trackHash, tdb->table);
     if (tdb == NULL)
         errAbort("Can't find track for table %s in wgEncodeDownloadDirKeeper", tdb->table);
     }
 return trackDbTopLevelSelfOrParent(tdb);
 }
 
 static char *htmlStringForDownloadsLink(char *database, struct trackDb *tdb,char *name,boolean nameIsFile,
         struct hash *trackHash)
 // Returns an HTML string for a downloads link
 {
 // Downloads directory if this is ENCODE
 if(trackDbSetting(tdb, "wgEncode") != NULL)
     {
     struct trackDb *dirKeeper = wgEncodeDownloadDirKeeper(database, tdb, trackHash);
+    char *actualName = (sameWord(dirKeeper->type,"downloadsOnly")?dirKeeper->track:tdb->table);
     struct dyString *dyLink = dyStringCreate("<A HREF=\"http://%s/goldenPath/%s/%s/%s/%s\" title='Download file' TARGET=ucscDownloads>%s</A>",
             hDownloadsServer(),
             trackDbSettingOrDefault(dirKeeper, "origAssembly",database),
-            ENCODE_DCC_DOWNLOADS, dirKeeper->table, (nameIsFile?name:""), name);
+            ENCODE_DCC_DOWNLOADS, actualName, (nameIsFile?name:""), name);
     return dyStringCannibalize(&dyLink);
     }
 return NULL;
 }
 
 static boolean makeNamedDownloadsLink(char *database, struct trackDb *tdb,char *name,
 	struct hash *trackHash)
 // Make a downloads link (if appropriate and then returns TRUE)
 {
 char *htmlString = htmlStringForDownloadsLink(database,tdb,name,FALSE,trackHash);
 if (htmlString == NULL)
     return FALSE;
 
 printf("%s", htmlString);
 freeMem(htmlString);
@@ -1967,47 +1968,48 @@
 	boolean leafOnly)
 /* Recursively add trackList to trackHash */
 {
 struct trackDb *tdb;
 for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
     {
     if (hTrackOnChrom(tdb, chrom))
 	{
 	if (tdb->subtracks == NULL || !leafOnly)
 	    hashAdd(trackHash, tdb->track, tdb);
 	}
     rAddTrackListToHash(trackHash, tdb->subtracks, chrom, leafOnly);
     }
 }
 
-struct hash *makeTrackHashWithComposites(char *database, char *chrom,
-                                        bool withComposites)
-/* Make hash of trackDb items for this chromosome, including composites,
-   not just the subtracks. */
+struct hash *trackHashMakeWithComposites(char *db,char *chrom,struct trackDb **tdbList,bool withComposites)
+// Make hash of trackDb items for this chromosome, including composites, not just the subtracks.
+// May pass in prepopulated trackDb list, or may receive the trackDb list as an inout.
 {
-struct trackDb *tdbs = hTrackDb(database);
+struct trackDb *theTdbs = NULL;
+if (tdbList == NULL || *tdbList == NULL)
+    {
+    theTdbs = hTrackDb(db);
+    if (tdbList != NULL)
+        *tdbList = theTdbs;
+    }
+else
+    theTdbs = *tdbList;
 struct hash *trackHash = newHash(7);
-rAddTrackListToHash(trackHash, tdbs, chrom, !withComposites);
+rAddTrackListToHash(trackHash, theTdbs, chrom, !withComposites);
 return trackHash;
 }
 
-struct hash *makeTrackHash(char *database, char *chrom)
-/* Make hash of trackDb items for this chromosome. */
-{
-return makeTrackHashWithComposites(database, chrom, FALSE);
-}
-
 /****** Stuff for acembly related options *******/
 
 static char *acemblyOptions[] = {
     "all genes",
     "main",
     "putative",
 };
 
 enum acemblyOptEnum acemblyStringToEnum(char *string)
 /* Convert from string to enum representation. */
 {
 int x = stringIx(string, acemblyOptions);
 if (x < 0)
    errAbort("hui::acemblyStringToEnum() - Unknown option %s", string);
 return x;
@@ -3759,374 +3761,402 @@
     }
 return date;
 }
 
 static void cfgLinkToDependentCfgs(struct cart *cart, struct trackDb *tdb,char *prefix)
 /* Link composite or view level controls to all associateled lower level controls */
 {
 if (!cartVarExists(cart, "ajax") && tdbIsComposite(tdb))
 #ifdef SUBTRACK_CFG_POPUP
     printf("<script type='text/javascript'>registerViewOnchangeAction('%s')</script>\n",prefix);
 #else///ifndef SUBTRACK_CFG_POPUP
     printf("<script type='text/javascript'>compositeCfgRegisterOnchangeAction(\"%s\")</script>\n",prefix);
 #endif///ndef SUBTRACK_CFG_POPUP
 }
 
-static void compositeUiSubtracks(char *db, struct cart *cart, struct trackDb *parentTdb,
-                 boolean selectedOnly, char *primarySubtrack, struct hash *trackHash)
+static void compositeUiSubtracks(char *db, struct cart *cart, struct trackDb *parentTdb,struct hash *trackHash)
 /* Display list of subtracks and descriptions with checkboxes to control visibility and possibly other
  * nice things including links to schema and metadata and a release date. */
 {
-boolean doColorPatch = trackDbSettingOn(parentTdb, "showSubtrackColorOnUi");
 struct trackDb *subtrack;
-char *primaryType = getPrimaryType(primarySubtrack, parentTdb);
-char htmlIdentifier[SMALLBUF];
 struct dyString *dyHtml = newDyString(SMALLBUF);
-char *colors[2]   = { COLOR_BG_DEFAULT,
-                      COLOR_BG_ALTDEFAULT };
+//char *colors[2]   = { COLOR_BG_DEFAULT,
+//                      COLOR_BG_ALTDEFAULT };
+char *colors[2]   = { "bgLevel1",
+                      "bgLevel1" };
 int colorIx = COLOR_BG_DEFAULT_IX; // Start with non-default allows alternation
 #ifndef SUBTRACK_CFG_POPUP
 boolean dependentCfgsNeedBinding = FALSE;
 #endif///ndef SUBTRACK_CFG_POPUP
 
 // Get list of leaf subtracks to work with
 struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks);
 
 // Look for dividers, heirarchy, dimensions, sort and dragAndDrop!
 char **lastDivide = NULL;
 dividers_t *dividers = dividersSettingGet(parentTdb);
 if(dividers)
     lastDivide = needMem(sizeof(char*)*dividers->count);
 hierarchy_t *hierarchy = hierarchySettingGet(parentTdb);
 
 membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,NULL);
 int dimCount=0,di;
 for(di=0;di<membersForAll->dimMax;di++) { if(membersForAll->members[di]) dimCount++; }
 sortOrder_t* sortOrder = sortOrderGet(cart,parentTdb);
 boolean preSorted = FALSE;
 boolean useDragAndDrop = sameOk("subTracks",trackDbSetting(parentTdb, "dragAndDrop"));
 
+// Table wraps around entire list so that "Top" link can float to the correct place.
 printf("<table><tr><td class='windowSize'>");
 printf("<A NAME='DISPLAY_SUBTRACKS'></A>");
 makeTopLink(parentTdb);
 
-// Now we can start in on the table of subtracks
+//printf("<style type='text/css'>td {padding: 0px 5px 0px;}</style>");
+
+// Now we can start in on the table of subtracks  It may be sortable and/or dragAndDroppable
 printf("\n<TABLE CELLSPACING='2' CELLPADDING='0' border='0'");
-if(sortOrder != NULL)
-    {
-    printf(" id='subtracks.%s.sortable'",parentTdb->track);
     dyStringClear(dyHtml);
-    dyStringPrintf(dyHtml, "tableSortable");
-    colorIx = COLOR_BG_ALTDEFAULT_IX;
-    }
-else
-    printf(" id='subtracks.%s'",parentTdb->track);
+if (sortOrder != NULL)
+    dyStringPrintf(dyHtml, "sortable");
 if(useDragAndDrop)
     {
     if(dyStringLen(dyHtml) > 0)
         dyStringAppendC(dyHtml,' ');
     dyStringPrintf(dyHtml, "tableWithDragAndDrop");
-    printf(" class='%s'",dyStringContents(dyHtml));
-    dyStringClear(dyHtml);
+    }
+if (dyStringLen(dyHtml) > 0)
+    {
+    printf(" class='subtracks %s'",dyStringContents(dyHtml));
     colorIx = COLOR_BG_ALTDEFAULT_IX;
     }
+if (sortOrder != NULL)
+    puts("><THEAD class=sortable>");
+else
 puts("><THEAD>");
 
-if (!primarySubtrack)
-    {
-    char javascript[JBUFSIZE];
+// First table row contains the display "selected/visible" or "all" radio buttons
     boolean displayAll = sameString(cartUsualString(cart, "displaySubtracks", "all"), "all");
-    boolean restrictions = FALSE;
-    for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next)
-        {
-	subtrack = subtrackRef->val;
-        (void)metadataForTable(db,subtrack,NULL);
-        const char *date = metadataFindValue(subtrack,"dateUnrestricted");
-        if(date != NULL) // Note this is stale memory (just freed), but non-NULL means found.
-            {
-            restrictions = TRUE;
-            break;
-            }
-        }
-
+boolean doColorPatch = trackDbSettingOn(parentTdb, "showSubtrackColorOnUi");
     int colspan = 3;
     if (sortOrder != NULL)
         colspan = sortOrder->count+2;
     if (doColorPatch)
         colspan += 1;
-    printf("<TR");
-    if(useDragAndDrop)
-        printf(" id=\"noDrag\" class='nodrop nodrag'");
-    printf(">");
+printf("<TR%s>",useDragAndDrop?" id='noDrag' class='nodrop nodrag'":"");
     printf("<TD colspan='%d'><B>List subtracks:&nbsp;", colspan);
+char javascript[JBUFSIZE];
     safef(javascript, sizeof(javascript), "onclick=\"showOrHideSelectedSubtracks(true);\"");
     cgiMakeOnClickRadioButton("displaySubtracks", "selected", !displayAll,javascript);
     puts("only selected/visible &nbsp;&nbsp;");
     safef(javascript, sizeof(javascript), "onclick=\"showOrHideSelectedSubtracks(false);\"");
     cgiMakeOnClickRadioButton("displaySubtracks", "all", displayAll,javascript);
     printf("all</B>");
     if(slCount(subtrackRefList) > 5)
         printf("&nbsp;&nbsp;&nbsp;&nbsp;(<FONT class='subCBcount'></font>)");
     puts("</TD>");
 
-    if(sortOrder != NULL)   // Add some sort buttons
+// Add column headers which are sort button links
+if (sortOrder != NULL)
         {
         puts("<TD colspan=5>&nbsp;</TD></TR>");
-        printf("<TR id=\"%s.sortTr\" class='nodrop nodrag'>\n",parentTdb->track);     // class='nodrop nodrag'
-        printf("<TD>&nbsp;<INPUT TYPE=HIDDEN NAME='%s' id='%s' VALUE=\"%s\"></TD>", sortOrder->htmlId, sortOrder->htmlId,sortOrder->sortOrder); // keeing track of priority
+    printf("<TR id=\"subtracksHeader\" class='nodrop nodrag sortable'>\n");
+    printf("<TH>&nbsp;<INPUT TYPE=HIDDEN NAME='%s' class='sortOrder' VALUE=\"%s\"></TH>\n", sortOrder->htmlId, sortOrder->sortOrder); // keeing track of sortOrder
         // Columns in tdb order (unchanging), sort in cart order (changed by user action)
         int sIx=0;
         for(sIx=0;sIx<sortOrder->count;sIx++)
             {
-            printf ("<TH id='%s.%s.sortTh' abbr='%c' nowrap><A HREF='#nowhere' onclick=\"tableSortAtButtonPress(this,'%s');return false;\">%s</A><sup>%s",
-                parentTdb->track,sortOrder->column[sIx],
-		(sortOrder->forward[sIx]?'-':'+'),
-		sortOrder->column[sIx],sortOrder->title[sIx],
-		(sortOrder->forward[sIx]?"&darr;":"&uarr;"));
+        printf("<TH id='%s' class='sortable%s sort%d' abbr='use' nowrap title='Sort list on this column' onclick='tableSortAtButtonPress(this);'>%s",
+            sortOrder->column[sIx],(sortOrder->forward[sIx]?"":" sortRev"),sortOrder->order[sIx],sortOrder->title[sIx]);
+        printf("<sup>%s",(sortOrder->forward[sIx]?"&darr;":"&uarr;"));
             if (sortOrder->count > 1)
                 printf ("%d",sortOrder->order[sIx]);
-            puts ("</sup></TH>");
+        printf("</sup>");
+        puts ("</TH>");
             }
         puts("<TD>&nbsp;</TD>");
         }
-
     puts("<TH>&nbsp;</TH>");
-    //puts("<TH align=\"center\" nowrap>&nbsp;Table&nbsp;</TH>");
-    if(restrictions)
+
+// Determine whether there is a restricted until date column
+for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next)
+    {
+    subtrack = subtrackRef->val;
+    (void)metadataForTable(db,subtrack,NULL);
+    if (NULL != metadataFindValue(subtrack,"dateUnrestricted"))
         {
         printf("<TH align=\"center\" nowrap>&nbsp;");
         printf("<A HREF=\'%s\' TARGET=BLANK>Restricted Until</A>", ENCODE_DATA_RELEASE_POLICY);
         puts("&nbsp;</TH>");
+        break; // Don't need more than one
         }
     }
+puts("</TR></THEAD>"); // The end of the header section.
 
+// The subtracks need to be sorted by priority but only sortable and dragable will have non-default (cart) priorities to sort on
 if(sortOrder != NULL || useDragAndDrop)
     {
     preSorted = tdbRefSortPrioritiesFromCart(cart, &subtrackRefList); // preserves user's prev sort/drags
-    puts("</TR></THEAD><TBODY id='sortable_tbody'>");
+    puts("<TBODY class='sortable altColors'>");
     }
 else
     {
     slSort(&subtrackRefList, trackDbRefCmp);  // straight from trackDb.ra
     preSorted = TRUE;
-    puts("</TR></THEAD><TBODY>");
+    puts("<TBODY>");
     }
 
+// Finally the big "for loop" to list each subtrack as a table row.
 for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next)
     {
     subtrack = subtrackRef->val;
-    boolean isPrimary = FALSE;
     int ix;
+
+    // Determine whether subtrack is checked, visible, configurable, has group membership, etc.
     int fourState = subtrackFourStateChecked(subtrack,cart);
     boolean checkedCB = fourStateChecked(fourState);
     boolean enabledCB = fourStateEnabled(fourState);
-    isPrimary = (primarySubtrack &&
-         sameString(subtrack->track, primarySubtrack));
-    safef(htmlIdentifier, sizeof(htmlIdentifier), "%s_sel", subtrack->track);
-
-
-    if (primarySubtrack)
-        {
-        if (isPrimary)
-            {
-            puts("<TR><TD>");
-            cgiMakeHiddenBoolean(htmlIdentifier, TRUE);
-            puts("[on] ");
-            printf ("</TD><TD>%s [selected on main page]</TD></TR>\n",
-                subtrack->longLabel);
-            }
-        else if (hSameTrackDbType(primaryType, subtrack->type))
-            {
-            puts("<TR><TD>");
-            cgiMakeCheckBox(htmlIdentifier, checkedCB && enabledCB);
-            printf ("</TD><TD>%s</TD></TR>\n", subtrack->longLabel);
-            }
-        }
-    else
-        {
         eCfgType cType = cfgTypeFromTdb(subtrack,FALSE);
 #ifdef SUBTRACK_CFG_POPUP
         // Turn this off only if configurable explicitly set to off
         if (trackDbSettingClosestToHome(subtrack, "configurable") && trackDbSettingClosestToHomeOn(subtrack, "configurable") == FALSE)
 #else///ifndef SUBTRACK_CFG_POPUP
         if(trackDbSettingClosestToHomeOn(subtrack, "configurable") == FALSE)
 #endif///ndef SUBTRACK_CFG_POPUP
             cType = cfgNone;
         membership_t *membership = subgroupMembershipGet(subtrack);
-            {
+
             if(sortOrder == NULL && !useDragAndDrop)
                 {
                 if( divisionIfNeeded(lastDivide,dividers,membership) )
                     colorIx = (colorIx == COLOR_BG_DEFAULT_IX ? COLOR_BG_ALTDEFAULT_IX : COLOR_BG_DEFAULT_IX);
                 }
 
+    // Start the TR which must have an id that is directly related to the checkBox id
             char *id = checkBoxIdMakeForTrack(subtrack,membersForAll->members,membersForAll->dimMax,membership); // view is known tag
-            printf("<TR valign='top' BGCOLOR=\"%s\"",colors[colorIx]);
-            if(useDragAndDrop)
-                printf(" class='trDraggable'");
+    printf("<TR valign='top' class='%s%s'",colors[colorIx],(useDragAndDrop?" trDraggable":""));
+    printf(" id=tr_%s p%s>\n",id,(!displayAll?" style='display:none'":""));
 
-            printf(" id=\"tr_%s\" nowrap%s>\n",id,(selectedOnly?" style='display:none'":""));
-            printf("<TD%s",(enabledCB?"":" title='view is hidden'"));
-            if (useDragAndDrop)
-                printf(" class='dragHandle' title='Drag to reorder'>");
-            else
-                printf(">");
+    // Now the TD that holds the checkbox
+    printf("<TD%s%s>",
+           (enabledCB?"":" title='view is hidden'"),
+           (useDragAndDrop?" class='dragHandle' title='Drag to reorder'":""));
+
+    // The checkbox has identifying classes including subCB and the tag for each dimension (e.g. class='subCB GM12878 CTCF Peak')
             dyStringClear(dyHtml);
-            dyStringAppend(dyHtml, "subCB");
+    dyStringAppend(dyHtml, "subCB"); // always first
             for(di=dimX;di<membersForAll->dimMax;di++)
                 {
                 if(membersForAll->members[di] && -1 != (ix = stringArrayIx(membersForAll->members[di]->groupTag, membership->subgroups, membership->count)))
                     dyStringPrintf(dyHtml," %s",membership->membership[ix]);
                 }
-            // Save view for last
             if(membersForAll->members[dimV] && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count)))
-                dyStringPrintf(dyHtml, " %s",membership->membership[ix]);
+        dyStringPrintf(dyHtml, " %s",membership->membership[ix]);  // Saved view for last
+
+    // And finally the checkBox is made!
+    char htmlIdentifier[SMALLBUF];
+    safef(htmlIdentifier, sizeof(htmlIdentifier), "%s_sel", subtrack->track);
             cgiMakeCheckBoxFourWay(htmlIdentifier,checkedCB,enabledCB,id,dyStringContents(dyHtml),"onclick='matSubCbClick(this);' style='cursor:pointer'");
             if (useDragAndDrop)
                 printf("&nbsp;");
 
+    // TODO: make a "view" dropdown (fake to save rendering time) and a configurable wrench here right after the checkbox
+
+    // A hidden field to keep track of subtrack order if it could change
             if(sortOrder != NULL || useDragAndDrop)
                 {
                 safef(htmlIdentifier, sizeof(htmlIdentifier), "%s.priority", subtrack->track);
                 float priority = (float)cartUsualDouble(cart, htmlIdentifier, subtrack->priority);
-                printf("<INPUT TYPE=HIDDEN NAME='%s' id='%s' VALUE=\"%.0f\">", htmlIdentifier, htmlIdentifier, priority); // keeing track of priority
+        printf("<INPUT TYPE=HIDDEN NAME='%s' class='trPos' VALUE=\"%.0f\">", htmlIdentifier, priority); // keeing track of priority
                 }
 
+    // A color patch which helps distinguish subtracks in some types of composites
             if (doColorPatch)
                 {
                 printf("<TD BGCOLOR='#%02X%02X%02X'>&nbsp;&nbsp;&nbsp;&nbsp;</TD>",
                         subtrack->colorR, subtrack->colorG, subtrack->colorB);
                 }
+
+    // Subtrack configuration requires a field that is a link to an embedded (or popup) dialog
 #ifdef SUBTRACK_CFG_POPUP
-    #define CFG_SUBTRACK_LINK  "<A HREF='#a_cfg_%s' onclick='return popUpSubtrackCfg(\"%s\",\"%s\");' title='%s'>%s</A>\n"
+    #define CFG_SUBTRACK_LINK  "<A HREF='#a_cfg_%s' onclick='return popUpSubtrackCfg(\"%s\",\"%s\");' title='%s'>%s</A>"
     #define MAKE_CFG_SUBTRACK_LINK(table,label,title) printf(CFG_SUBTRACK_LINK, (table),(table),(label),(label),(title))
             struct dyString *dyLabel = newDyString(128);
 #else///ifndef SUBTRACK_CFG_POPUP
-    #define CFG_SUBTRACK_LINK  "<A HREF='#a_cfg_%s' onclick='return subtrackCfgShow(\"%s\");' title='Subtrack Configuration'>%s</A>\n"
+    #define CFG_SUBTRACK_LINK  "<A HREF='#a_cfg_%s' onclick='return subtrackCfgShow(\"%s\");' title='Subtrack Configuration'>%s</A>"
     #define MAKE_CFG_SUBTRACK_LINK(table,title) printf(CFG_SUBTRACK_LINK, (table),(table),(title))
 #endif///ndef SUBTRACK_CFG_POPUP
+
+    // If sortable, then there must be a column per sortable dimension
             if(sortOrder != NULL)
                 {
                 int sIx=0;
                 for(sIx=0;sIx<sortOrder->count;sIx++)
                     {
                     ix = stringArrayIx(sortOrder->column[sIx], membership->subgroups, membership->count);                        // TODO: Sort needs to expand from subGroups to labels as well
                     if(ix >= 0)
                         {
                         char *titleRoot=labelRoot(membership->titles[ix],NULL);
-                        printf ("<TD id='%s' nowrap abbr='%s' align='left'>&nbsp;",sortOrder->column[sIx],membership->membership[ix]);
+                // Each sortable column requires hidden goop (in the "abbr" field currently) which is the actual sort on value
+                printf ("<TD id='%s_%s' nowrap abbr='%s' align='left'>&nbsp;",subtrack->track,sortOrder->column[sIx],membership->membership[ix]);
 #ifdef SUBTRACK_CFG_POPUP
                         dyStringPrintf(dyLabel,"%s ",titleRoot);
-                        if (cType != cfgNone && sameString("view",sortOrder->column[sIx]))
+                if (cType != cfgNone && sameString("view",sortOrder->column[sIx])) // configure link is on view currenntly  TODO: make a wrench next to check box/view
                             {
                             dyStringAppend(dyLabel,"Configuration");
                             MAKE_CFG_SUBTRACK_LINK(subtrack->track,dyStringContents(dyLabel),titleRoot);
                             }
 #else///ifndef SUBTRACK_CFG_POPUP
                         if(cType != cfgNone && sameString("view",sortOrder->column[sIx]))
                             MAKE_CFG_SUBTRACK_LINK(subtrack->track,titleRoot);  // FIXME: Currently configurable under sort only supported when multiview
 #endif///ndef SUBTRACK_CFG_POPUP
                         else
-                            printf("%s\n",titleRoot);
+                    printf("%s",titleRoot);
                         puts ("</TD>");
                         freeMem(titleRoot);
                         }
                     }
                 }
-            else
+    else  // Non-sortable tables do not have sort by columns but will display a short label (which may be a configurable link)
                 {
                 printf ("<TD nowrap='true'>&nbsp;");
                 indentIfNeeded(hierarchy,membership);
 #ifdef SUBTRACK_CFG_POPUP
-                if (cType != cfgNone && cType != cfgWigMaf)  // FIXME: wigMaf restriction is temporary unto configurable off is set
+        if (cType != cfgNone && cType != cfgWigMaf)  // FIXME: wigMaf restriction is temporary until configureByPopup off is set
                     MAKE_CFG_SUBTRACK_LINK(subtrack->track,subtrack->shortLabel,subtrack->shortLabel);
 #else///ifndef SUBTRACK_CFG_POPUP
                 if(cType != cfgNone)
                     MAKE_CFG_SUBTRACK_LINK(subtrack->track,subtrack->shortLabel);
 #endif///ndef SUBTRACK_CFG_POPUP
                 else
-                    printf("%s\n",subtrack->shortLabel);
+            printf("%s",subtrack->shortLabel);
                 puts ("</TD>");
                 }
 #ifdef SUBTRACK_CFG_POPUP
             dyStringFree(&dyLabel);
 #endif///def SUBTRACK_CFG_POPUP
-            printf ("<TD nowrap='true' title='select to copy'><div>&nbsp;%s", subtrack->longLabel);
+
+    // The long label column (note that it may have a "..." that allows getting at all the metadata)
+    printf ("<TD nowrap title='select to copy'>&nbsp;%s", subtrack->longLabel);
             if(trackDbSetting(parentTdb, "wgEncode") && trackDbSetting(subtrack, "accession"))
                 printf (" [GEO:%s]", trackDbSetting(subtrack, "accession"));
             compositeMetadataToggle(db,subtrack,"...",TRUE,FALSE, trackHash);
-            printf("</div>");
+    printf("&nbsp;");
 
 #ifndef SUBTRACK_CFG_POPUP
+    // Embedded cfg dialogs are within the TD that contains the longLabel.  This allows a wide item to be embedded in the table
             if(cType != cfgNone)
                 {
                 dependentCfgsNeedBinding = TRUE; // configurable subtrack needs to be bound to composite settings
     #define CFG_SUBTRACK_DIV "<DIV id='div_%s_cfg'%s><INPUT TYPE=HIDDEN NAME='%s' value='%s'>\n"
     #define MAKE_CFG_SUBTRACK_DIV(table,cfgVar,open) printf(CFG_SUBTRACK_DIV,(table),((open)?"":" style='display:none'"),(cfgVar),((open)?"on":"off"))
                 safef(htmlIdentifier,sizeof(htmlIdentifier),"%s.childShowCfg",subtrack->track);
                 boolean open = cartUsualBoolean(cart, htmlIdentifier,FALSE);
                 MAKE_CFG_SUBTRACK_DIV(subtrack->track,htmlIdentifier,open);
                 safef(htmlIdentifier,sizeof(htmlIdentifier),"%s",subtrack->track);
                 cfgByCfgType(cType,db,cart,subtrack,htmlIdentifier,"Subtrack",TRUE);
-                puts("</DIV>\n");
+        printf("</DIV>");
                 }
 #endif///ndef SUBTRACK_CFG_POPUP
-            printf("<TD nowrap>&nbsp;");
+
+    // A schema link for each track
+    printf("</td>\n<TD nowrap>&nbsp;");
             makeSchemaLink(db,subtrack,"schema");
-            puts("&nbsp;");
+    printf("&nbsp;");
 
+    // Do we have a restricted until date?
             char *dateDisplay = encodeRestrictionDateDisplay(db,subtrack);
             if (dateDisplay)
-                printf("</TD><TD align=\"CENTER\">&nbsp;%s&nbsp;", dateDisplay);
+        printf("</TD>\n<TD align=\"CENTER\">&nbsp;%s&nbsp;", dateDisplay);
 
-            puts("</TD></TR>");
+    // End of row and free ourselves of this subtrack
+    puts("</TD></TR>\n");
             checkBoxIdFree(&id);
-            }
         subgroupMembershipFree(&membership);
         }
-    }
+
+// End of the table
 puts("</TBODY><TFOOT></TFOOT>");
 puts("</TABLE>");
 printf("</td></tr></table>");
+
+// Count of subtracks is filled in by javascript.
 if(slCount(subtrackRefList) > 5)
     puts("&nbsp;&nbsp;&nbsp;&nbsp;<FONT class='subCBcount'></font>");
 puts("<P>");
-if (!primarySubtrack)
+
+// Tying subtracks with matrix and subtrack cfgs with views requires javascript help
     puts("<script type='text/javascript'>matInitializeMatrix();</script>");
 #ifndef SUBTRACK_CFG_POPUP
 if(dependentCfgsNeedBinding)
     cfgLinkToDependentCfgs(cart,parentTdb,parentTdb->track);
 #endif//ndef SUBTRACK_CFG_POPUP
+
+// Finally we are free of all this
 membersForAllSubGroupsFree(parentTdb,&membersForAll);
 dyStringFree(&dyHtml)
 sortOrderFree(&sortOrder);
 dividersFree(&dividers);
 hierarchyFree(&hierarchy);
 }
 
-static void compositeUiAllSubtracks(char *db, struct cart *cart, struct trackDb *tdb,
-				    char *primarySubtrack, struct hash *trackHash)
-/* Show checkboxes for all subtracks, not just selected ones. */
+static void compositeUiSubtracksMatchingPrimary(char *db, struct cart *cart, struct trackDb *parentTdb,char *primarySubtrack)
+/* Display list of subtracks associated with a primary subtrack for the hgTables merge function */
 {
-compositeUiSubtracks(db, cart, tdb, FALSE, primarySubtrack, trackHash);
-}
+assert(primarySubtrack != NULL);
+char *primaryType = getPrimaryType(primarySubtrack, parentTdb);
+char htmlIdentifier[SMALLBUF];
+
+// Get list of leaf subtracks to work with and sort them
+struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks);
+if (NULL != trackDbSetting(parentTdb, "sortOrder") || NULL != trackDbSetting(parentTdb, "dragAndDrop"))
+    tdbRefSortPrioritiesFromCart(cart, &subtrackRefList); // preserves user's prev sort/drags
+else
+    slSort(&subtrackRefList, trackDbRefCmp);  // straight from trackDb.ra
+
+// Now we can start in on the table of subtracks
+printf("\n<TABLE CELLSPACING='2' CELLPADDING='0' border='0' id='subtracks.%s'><THEAD>\n</TR></THEAD><TBODY>\n",parentTdb->track);
 
-static void compositeUiSelectedSubtracks(char *db, struct cart *cart, struct trackDb *tdb,
-					 char *primarySubtrack, struct hash *trackHash)
-/* Show checkboxes only for selected subtracks. */
+for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next)
 {
-compositeUiSubtracks(db, cart, tdb, TRUE, primarySubtrack, trackHash);
+    struct trackDb *subtrack = subtrackRef->val;
+    int fourState = subtrackFourStateChecked(subtrack,cart);
+    boolean checkedCB = fourStateChecked(fourState);
+    boolean enabledCB = fourStateEnabled(fourState);
+    safef(htmlIdentifier, sizeof(htmlIdentifier), "%s_sel", subtrack->track);
+
+    if (sameString(subtrack->track, primarySubtrack))
+        {
+        puts("<TR><TD>");
+        cgiMakeHiddenBoolean(htmlIdentifier, TRUE);
+        puts("[on] ");
+        printf ("</TD><TD>%s [selected on main page]</TD></TR>\n",
+            subtrack->longLabel);
+        }
+    else if (hSameTrackDbType(primaryType, subtrack->type))
+        {
+        puts("<TR><TD>");
+        cgiMakeCheckBox(htmlIdentifier, checkedCB && enabledCB);
+        printf ("</TD><TD>%s</TD></TR>\n", subtrack->longLabel);
+        }
+    }
+puts("</TBODY><TFOOT></TFOOT>");
+puts("</TABLE>");
+if (slCount(subtrackRefList) > 5)
+    puts("&nbsp;&nbsp;&nbsp;&nbsp;<FONT class='subCBcount'></font>");
+puts("<P>");
+if (!primarySubtrack)
+    puts("<script type='text/javascript'>matInitializeMatrix();</script>");
 }
 
 static void makeAddClearSubmitTweak(char javascript[JBUFSIZE], char *formName,
 				    char *buttonVar, char *label)
 /* safef into javascript a sequence of commands that will force a refresh
  * of this same form, updating the values of whatever variables are necessary
  * to say what we want to do. */
 {
 safef(javascript, JBUFSIZE*sizeof(char),
       "document.%s.action = '%s'; document.%s.%s.value='%s'; "
       "document.%s.submit();",
       formName, cgiScriptName(), formName, buttonVar, label,
       formName);
 }
 
@@ -6133,31 +6163,31 @@
         const char * mdbVal = metadataFindValue(childTdb,mdbVar); // one for each is enough
         if(mdbVal != NULL)
             {
             if(!first)
                 dyStringAppendC(dyLink,',');
             dyStringAppend(dyLink,(char *)mdbVal);
             first = FALSE;
             }
         }
     }
 dyStringPrintf(dyLink,VOCAB_MULTILINK_END,members->groupTitle,members->groupTitle);
 freeMem(vocab);
 return dyStringCannibalize(&dyLink);
 }
 
-static boolean hCompositeUiByFilter(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName)
+static boolean compositeUiByFilter(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName)
 /* UI for composite tracks: filter subgroups by multiselects to select subtracks. */
 {
 membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,cart);
 if(membersForAll == NULL || membersForAll->filters == FALSE) // Not Matrix or filters
     return FALSE;
 jsIncludeFile("ui.core.js",NULL);
 jsIncludeFile("ui.dropdownchecklist.js",NULL);
 webIncludeResourceFile("ui.dropdownchecklist.css");
 
 // TODO:
 // 1) Scroll long lists should be configurable through tdb setting
 //    #define FILTER_COMPOSITE_OPEN_SIZE 16
 // 2) columnCount (Number of filterBoxes per row) should be configurable through tdb setting
 
 printf("<B>Filter subtracks %sby:</B> (select multiple %sitems - %s)<BR>\n",
@@ -6213,31 +6243,31 @@
 
     #ifdef FILTER_COMPOSITE_ONLYONE
     if(membersForAll->members[dimIx]->fcType == fctOneOnly)
         printf(" (select only one)");
     #endif///def FILTER_COMPOSITE_ONLYONE
 
     printf("</TD><TD width='20'></TD>\n");
     }
 printf("</TR></TABLE>\n");
 
 puts("<BR>\n");
 
 return TRUE;
 }
 
-static boolean hCompositeUiByMatrix(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName)
+static boolean compositeUiByMatrix(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName)
 /* UI for composite tracks: matrix of checkboxes. */
 {
 //int ix;
 char objName[SMALLBUF];
 
 membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,cart);
 if(membersForAll == NULL || membersForAll->dimensions == NULL) // Not Matrix!
     return FALSE;
 
 int ixX,ixY;
 members_t *dimensionX = membersForAll->members[dimX];
 members_t *dimensionY = membersForAll->members[dimY];
 
 // use array of char determine all the cells (in X,Y,Z dimensions) that are actually populated
 char *value;
@@ -6278,31 +6308,31 @@
                 {
                 if(subtrackInAllCurrentABCs(subtrack,membersForAll))  // Only bother if the subtrack is found in all ABC dims checked
                     {
                     enabd[ixX][ixY]++;
                     if(fourStateChecked(fourState) == 1)
                         chked[ixX][ixY]++;
                     }
                 }
             }
         }
     }
 
 // If there is no matrix and if there is a filterComposite, then were are done.
 if(dimensionX == NULL && dimensionY == NULL)
     {
-    if (hCompositeUiByFilter(db, cart, parentTdb, formName))
+    if (compositeUiByFilter(db, cart, parentTdb, formName))
         return FALSE;
     }
 
 // Tell the user what to do:
 char javascript[JBUFSIZE];
 //puts("<B>Select subtracks by characterization:</B><BR>");
 printf("<B>Select subtracks by ");
 if(dimensionX && !dimensionY)
     safef(javascript, sizeof(javascript), "%s:</B>",dimensionX->groupTitle);
 else if(!dimensionX && dimensionY)
     safef(javascript, sizeof(javascript), "%s:</B>",dimensionY->groupTitle);
 else if(dimensionX && dimensionY)
     safef(javascript, sizeof(javascript), "%s and %s:</B>",dimensionX->groupTitle,dimensionY->groupTitle);
 else
     safef(javascript, sizeof(javascript), "multiple variables:</B>");
@@ -6410,55 +6440,55 @@
                     }
                 }
             }
         if(dimensionX && cntX>MATRIX_RIGHT_BUTTONS_AFTER)
             matrixYheadings(db,parentTdb, membersForAll,ixY,FALSE);
         puts("</TR>\n");
         }
     }
 if(dimensionY && cntY>MATRIX_BOTTOM_BUTTONS_AFTER)
     matrixXheadings(db,parentTdb,membersForAll,FALSE);
 
 puts("</TD></TR></TABLE>");
 puts("<BR>\n");
 
 // If any filter additional filter composites, they can be added at the end.
-hCompositeUiByFilter(db, cart, parentTdb, formName);
+compositeUiByFilter(db, cart, parentTdb, formName);
 
 return TRUE;
 }
 
-static boolean hCompositeUiAllButtons(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName)
+static boolean compositeUiAllButtons(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName)
 /* UI for composite tracks: all/none buttons only (as opposed to matrix or lots of buttons */
 {
 if (trackDbCountDescendantLeaves(parentTdb) <= 1)
     return FALSE;
 
 if(dimensionsExist(parentTdb))
     return FALSE;
 
 #define PM_BUTTON_GLOBAL "<IMG height=18 width=18 onclick=\"matSubCBsCheck(%s);\" id='btn_%s' src='../images/%s'>"
 #define    BUTTON_PLUS_ALL_GLOBAL()  printf(PM_BUTTON_GLOBAL,"true",  "plus_all",   "add_sm.gif")
 #define    BUTTON_MINUS_ALL_GLOBAL() printf(PM_BUTTON_GLOBAL,"false","minus_all","remove_sm.gif")
 printf("<P><B>Select subtracks:</B><P>All:&nbsp;");
 BUTTON_PLUS_ALL_GLOBAL();
 BUTTON_MINUS_ALL_GLOBAL();
 puts("</P>");
 return TRUE;
 }
 
-static boolean hCompositeUiNoMatrix(char *db, struct cart *cart, struct trackDb *parentTdb,
+static boolean compositeUiNoMatrix(char *db, struct cart *cart, struct trackDb *parentTdb,
           char *primarySubtrack, char *formName)
 /* UI for composite tracks: subtrack selection.  This is the default UI
 without matrix controls. */
 {
 int i, j, k;
 char *words[SMALLBUF];
 char option[SMALLBUF];
 int wordCnt;
 char javascript[JBUFSIZE];
 char *primaryType = getPrimaryType(primarySubtrack, parentTdb);
 char *name, *value;
 char buttonVar[32];
 char setting[] = "subGroupN";
 char *button;
 struct trackDb *subtrack;
@@ -6596,101 +6626,98 @@
             }
         }
     puts ("</TABLE>");
     }
     return TRUE;
 }
 
 void hCompositeUi(char *db, struct cart *cart, struct trackDb *tdb,
 		  char *primarySubtrack, char *fakeSubmit, char *formName, struct hash *trackHash)
 /* UI for composite tracks: subtrack selection.  If primarySubtrack is
  * non-NULL, don't allow it to be cleared and only offer subtracks
  * that have the same type.  If fakeSubmit is non-NULL, add a hidden
  * var with that name so it looks like it was pressed. */
 {
 bool hasSubgroups = (trackDbSetting(tdb, "subGroup1") != NULL);
-boolean displayAll =
-    sameString(cartUsualString(cart, "displaySubtracks", "all"), "all");
 boolean isMatrix = dimensionsExist(tdb);
 boolean viewsOnly = FALSE;
 
 if (!cartVarExists(cart, "ajax"))
     {
     if(trackDbSetting(tdb, "dragAndDrop") != NULL)
         jsIncludeFile("jquery.tablednd.js", NULL);
     jsIncludeFile("ajax.js",NULL);
     #ifdef TABLE_SCROLL
     jsIncludeFile("jquery.fixedtable.js",NULL);
     #endif//def TABLE_SCROLL
     }
 jsIncludeFile("hui.js",NULL);
 
 #ifdef SUBTRACK_CFG_POPUP
 printf("<div id='popit' style='display: none'></div>");
 cgiMakeHiddenVar("db", db);
 printf("<input type=HIDDEN id='track' value='%s';</input>\n",tdb->track);
 #endif
 puts("<P>");
 if (trackDbCountDescendantLeaves(tdb) < MANY_SUBTRACKS && !hasSubgroups)
     {
-    compositeUiAllSubtracks(db, cart, tdb, primarySubtrack, trackHash);
+    if(primarySubtrack)
+        compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack);
+    else
+        compositeUiSubtracks(db, cart, tdb, trackHash);
     return;
     }
 if (fakeSubmit)
     cgiMakeHiddenVar(fakeSubmit, "submit");
 
 if(primarySubtrack == NULL)
     {
     if(subgroupingExists(tdb,"view"))
         {
         hCompositeDisplayViewDropDowns(db, cart,tdb);
         if(subgroupCount(tdb) <= 1)
             viewsOnly = TRUE;
         }
     if(!viewsOnly)
         {
         if(trackDbSettingOn(tdb, "allButtonPair"))
 	    {
-            hCompositeUiAllButtons(db, cart, tdb, formName);
+            compositeUiAllButtons(db, cart, tdb, formName);
 	    }
         else if (!hasSubgroups || !isMatrix || primarySubtrack)
 	    {
-            hCompositeUiNoMatrix(db, cart,tdb,primarySubtrack,formName);
+            compositeUiNoMatrix(db, cart,tdb,primarySubtrack,formName);
 	    }
         else
 	    {
-            hCompositeUiByMatrix(db, cart, tdb, formName);
+            compositeUiByMatrix(db, cart, tdb, formName);
 	    }
         }
 #ifdef SUBTRACK_CFG_POPUP
     if(primarySubtrack == NULL)
         cfgLinkToDependentCfgs(cart,tdb,tdb->track);  // Must be after views are set up to get view vis
     printf("<script type='text/javascript'>registerFormSubmit('mainForm');</script>\n");
 #endif
     }
 
 cartSaveSession(cart);
 cgiContinueHiddenVar("g");
 
-if(displayAll)
-    {
-    compositeUiAllSubtracks(db, cart, tdb, primarySubtrack, trackHash);
-    }
+if(primarySubtrack)
+    compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack);
 else
-    {
-    compositeUiSelectedSubtracks(db, cart, tdb, primarySubtrack, trackHash);
-    }
+    compositeUiSubtracks(db, cart, tdb, trackHash);
 
 if (primarySubtrack == NULL)  // primarySubtrack is set for tableBrowser but not hgTrackUi
     {
     if (trackDbCountDescendantLeaves(tdb) > 5)
         {
         cgiMakeButton("Submit", "Submit");
         puts("<P>");
         }
     }
 }
 
 boolean superTrackDropDownWithExtra(struct cart *cart, struct trackDb *tdb,
                                 int visibleChild,char *extra)
 /* Displays hide/show dropdown for supertrack.
  * Set visibleChild to indicate whether 'show' should be grayed