37f3d8e76d96d4d7530dabe536cf659109867a64
braney
  Sat Mar 8 09:50:51 2025 -0800
ongoing work on quickLift.   Output the entire composite if a track
within is visible

diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c
index 66d23dff50d..e19a7606de7 100644
--- src/hg/lib/trackHub.c
+++ src/hg/lib/trackHub.c
@@ -1507,57 +1507,47 @@
     {
     trashDirDateFile(&hubTn, "quickLift", "hub", ".txt");
     hubName = cloneString(hubTn.forCgi);
     cartSetString(cart, buffer, hubName);
     FILE *f = mustOpen(hubName, "a");
     outHubHeader(f, db);
     fclose(f);
     }
 
 if (fd >= 0)
     close(fd);
 
 return hubName;
 }
 
-static void dumpTdbAndParents(struct dyString *dy, struct trackDb *tdb, struct hash *existHash, struct hash *wantHash)
+static void dumpTdbAndChildren(struct dyString *dy, struct trackDb *tdb)
 /* Put a trackDb entry into a dyString, stepping up the tree for some variables. */
 {
-#ifdef NOTNOW  // don't dump the parents of tracks yet
-if (tdb->parent)
-    {
-    dumpTdbAndParents(dy, tdb->parent, existHash, NULL);
-    }
-
-hashStore(existHash, "track");
-#endif
 struct hashCookie cookie = hashFirst(tdb->settingsHash);
 struct hashEl *hel;
 while ((hel = hashNext(&cookie)) != NULL)
-    {   
-    if (!hashLookup(existHash, hel->name) && ((wantHash == NULL) || hashLookup(wantHash, hel->name)))    
     {   
     dyStringPrintf(dy, "%s %s\n", hel->name, (char *)hel->val);
-        hashStore(existHash, hel->name);
-        }
     }
 
-if (tdb->parent)
+if (tdb->subtracks)
+        {
+        for (tdb = tdb->subtracks; tdb; tdb = tdb->next)
             {
-    struct hash *newWantHash = newHash(4);
-    hashStore(newWantHash, "type"); // right now we only want type from parents
-    dumpTdbAndParents(dy, tdb->parent, existHash, newWantHash);
+            dyStringPrintf(dy, "\ntrack %s\nquickLifted on\navoidHandler on\n", trackHubSkipHubName(tdb->track));
+            dumpTdbAndChildren(dy, tdb);
+            }
         }
 }
 
 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;
     }
@@ -1595,114 +1585,186 @@
 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 dyString *trackDbString(struct trackDb *tdb)
 /* Convert a trackDb entry into a dyString. */
 {
 struct dyString *dy;
-struct hash *existHash = newHash(5);
 
 // add a note that the name based handler shouldn't be used on this track
 // add a note that this is a quickLifted track so the browser will accept tracks that aren't big*
 dy = dyStringNew(200);
 dyStringPrintf(dy, "track %s\nquickLifted on\navoidHandler on\n", trackHubSkipHubName(tdb->track));
-hashStore(existHash, "track");
     
-dumpTdbAndParents(dy, tdb, existHash, NULL);
+dumpTdbAndChildren(dy, tdb);
 
 return dy;
 }
 
-static void walkTree(FILE *f, struct cart *cart,  struct trackDb *tdb, struct dyString *visDy)
-/* walk tree looking for visible tracks. */
+static boolean validateOneTdb(char *db, struct trackDb *tdb)
 {
-for(; tdb; tdb = tdb->next)
+if (!( startsWith("bigBed", tdb->type) || \
+       startsWith("bigWig", tdb->type) || \
+       startsWith("bed ", tdb->type)))
     {
-    if (tdb->subtracks)
-        walkTree(f, cart, tdb->subtracks, visDy);
+    return FALSE;
+    }
+
+// make sure we have a bigDataUrl
+if (startsWith("bigBed", tdb->type) || \
+       startsWith("bigWig", tdb->type))
+    {
+    char *fileName = cloneString(trackDbSetting(tdb, "bigDataUrl"));
+
+    if (fileName == NULL)
+        {
+        struct sqlConnection *conn = hAllocConnTrack(db, tdb);
+        fileName = bbiNameFromSettingOrTable(tdb, conn, tdb->table);
+        hashAdd(tdb->settingsHash, "bigDataUrl", fileName);
+        }
+    }
+
+return TRUE;
+}
+
+static struct trackDb * validateTdbChildren(char *db, struct trackDb *tdb)
+/* return a list of the children that can be quick lifted */
+{
+struct trackDb *validTdbs = NULL;
+struct trackDb *nextTdb;
+unsigned count = 0;
+
+if (tdb->subtracks)  // this is a view, descend again
+    {
+    tdb->subtracks = validateTdbChildren(db, tdb->subtracks);
+
+    if (tdb->subtracks != NULL)
+        {
+        slAddHead(&validTdbs, tdb);
+        if (tdb->visibility)
+            count++;
+        }
+    }
 else
     {
-        if (!( startsWith("big", tdb->type) || startsWith("bed ", tdb->type)))
-            continue;
+    for(; tdb; tdb = nextTdb)
+        {
+        nextTdb = tdb->next;
+        if (validateOneTdb(db, tdb))
+            {
+            slAddHead(&validTdbs, tdb);
+            if (tdb->visibility)
+                count++;
+            }
+        }
+    }
+if (count)
+    return validTdbs;
+
+return NULL;
+}
+
+static boolean validateTdb(char *db, struct trackDb *tdb)
+// make sure we only output track types that can
+// be quickLifted.  Return true if we any tracks survive
+{
+if (tdb->subtracks)
+    {
+    tdb->subtracks = validateTdbChildren(db, tdb->subtracks);
+
+    if (tdb->subtracks == NULL)
+        return FALSE;
+    return TRUE;
+    }
+
+return validateOneTdb(db, tdb);
+}
+
+static void walkTree(FILE *f, char *db, struct cart *cart,  struct trackDb *tdb, struct dyString *visDy)
+/* walk tree looking for visible tracks. */
+{
+for(; tdb; tdb = tdb->next)
+    {
     boolean isVisible = FALSE;
-        if (tdb->parent == NULL)
+
+    if (tdb->parent == NULL)  // not in super track
         {
         char *cartVis = cartOptionalString(cart, tdb->track);
         if (cartVis != NULL)
             {
             tdb->visibility = hTvFromString(cartVis);
             }
         isVisible =  tdb->visibility != tvHide;
         }
-        else if (isParentVisible(cart, tdb) &&  isSubtrackVisible(cart, tdb))
+    else if (isParentVisible(cart, tdb) &&  isSubtrackVisible(cart, tdb)) // child of supertrack
         {
         char *cartVis = cartOptionalString(cart, tdb->parent->track);
-            if ((cartVis == NULL) && tdb->parent->parent)
-                cartVis = cartOptionalString(cart, tdb->parent->parent->track);
+        if (cartVis != NULL)
             tdb->visibility = hTvFromString(cartVis);
+        else if (tdbIsSuperTrack(tdb->parent))
+            tdb->visibility = tdb->parent->isShow;
         isVisible = TRUE;
         }
 
-        if (isVisible)
+    if (isVisible && validateTdb(db, tdb))
         {
         dyStringPrintf(visDy, "&%s=%s", tdb->track,hStringFromTv(tdb->visibility));
         //if (hashLookup(tdb->settingsHash, "customized") == NULL)
             {
             hashRemove(tdb->settingsHash, "maxHeightPixels");
             hashRemove(tdb->settingsHash, "superTrack");
             hashRemove(tdb->settingsHash, "subGroups");
             hashRemove(tdb->settingsHash, "polished");
             hashRemove(tdb->settingsHash, "noInherit");
             hashRemove(tdb->settingsHash, "group");
             hashRemove(tdb->settingsHash, "parent");
             }
 
         //hashReplace(tdb->settingsHash, "customized", "on");
 
         // is this a custom track?
         char *tdbType = trackDbSetting(tdb, "tdbType");
         if (tdbType != NULL)
             {
             hashReplace(tdb->settingsHash, "type", tdbType);
             hashReplace(tdb->settingsHash, "shortLabel", trackDbSetting(tdb, "name"));
             hashReplace(tdb->settingsHash, "longLabel", trackDbSetting(tdb, "description"));
             }
 
         struct dyString *dy = trackDbString(tdb);
 
         fprintf(f, "%s\n", dy->string);
         }
     }
 }
-}
 
 char *trackHubBuild(char *db, struct cart *cart, struct dyString *visDy)
 /* Build a track hub using trackDb and the cart. */
 {
 struct  trackDb *tdbList;
 struct grp *grpList;
 cartTrackDbInit(cart, &tdbList, &grpList, FALSE);
 
 char *filename = getHubName(cart, db);
 
 FILE *f = mustOpen(filename, "a");
 chmod(filename, 0666);
 
-walkTree(f, cart, tdbList, visDy);
+walkTree(f, db, cart, tdbList, visDy);
 fclose(f);
 
 return cloneString(filename);
 }
 
 struct grp *trackHubGetGrps()
 /* Get the groups defined by attached track hubs. */
 {
 return trackHubGrps;
 }