5c213974bb28e98d1b10ad9a86063101e684e5e3
braney
  Mon Oct 31 12:16:52 2022 -0700
add Jim's track duplication code

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index fad775c..adfe39c 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -53,30 +53,31 @@
 #include "jsHelper.h"
 #include "mafTrack.h"
 #include "hgConfig.h"
 #include "encode.h"
 #include "agpFrag.h"
 #include "imageV2.h"
 #include "suggest.h"
 #include "search.h"
 #include "errCatch.h"
 #include "iupac.h"
 #include "botDelay.h"
 #include "chromInfo.h"
 #include "extTools.h"
 #include "basicBed.h"
 #include "customFactory.h"
+#include "dupTrack.h"
 #include "genbank.h"
 #include "bigWarn.h"
 #include "wigCommon.h"
 #include "knetUdc.h"
 #include "hex.h"
 #include <openssl/sha.h>
 #include "customComposite.h"
 #include "chromAlias.h"
 #include "jsonWrite.h"
 #include "cds.h"
 #include "cacheTwoBit.h"
 #include "cartJson.h"
 
 //#include "bed3Sources.h"
 
@@ -6584,30 +6585,104 @@
 	    {
 	    if (wordCount != 3)
 		errAbort("Expecting 3 words in pix line");
 	    trackLayoutSetPicWidth(&tl, words[2]);
 	    }
 	}
     }
 for (ct = ctList; ct != NULL; ct = ct->next)
     {
     hasCustomTracks = TRUE;
     tg = newCustomTrack(ct);
     slAddHead(pTrackList, tg);
     }
 }
 
+static void rHashList(struct hash *hash, struct track *list)
+/* Add list of tracks to hash including subtracks */
+{
+struct track *track;
+for (track = list; track != NULL; track = track->next)
+    {
+    hashAdd(hash, track->track, track);
+    if (track->subtracks != NULL)
+       rHashList(hash, track->subtracks);
+    }
+}
+
+static struct hash *hashTracksAndSubtracksFromList(struct track *list)
+/* Make a hash and put all of tracks and subtracks on it. */
+{
+struct hash *hash = hashNew(12);
+rHashList(hash, list);
+return hash;
+}
+
+void makeDupeTracks(struct track **pTrackList)
+/* Make up dupe tracks and append to list. Have to also crawl
+ * through list to add subtracks */
+{
+struct dupTrack *dupList = dupTrackListFromCart(cart);
+if (dupList == NULL)
+    return;
+
+/* Make up hash of tracks for quick finding of sources */
+struct hash *trackHash = hashTracksAndSubtracksFromList(*pTrackList);
+
+struct dupTrack *dup;
+for (dup = dupList; dup != NULL; dup = dup->next)
+    {
+    struct track *source = hashFindVal(trackHash, dup->source);
+    if (source != NULL)
+        {
+	struct track *track = CloneVar(source);
+	struct trackDb *tdb = track->tdb = dupTdbFrom(source->tdb, dup);
+	track->track = dup->name;
+	track->shortLabel = tdb->shortLabel;
+	track->longLabel = tdb->longLabel;
+	struct trackDb *parentTdb = tdb->parent;
+	if (parentTdb == NULL)
+	    slAddHead(pTrackList, track);
+	else
+	    {
+	    if (tdbIsFolder(parentTdb))
+	        {
+		refAdd(&parentTdb->children, tdb);
+		slAddHead(pTrackList, track);
+		}
+	    else
+	        {
+		/* Add to parent Tdb */
+		slAddHead(&parentTdb->subtracks, tdb);
+
+		/* The parentTrack may correspond to the parent or grandParent tdb, look both places */
+		struct track *parentTrack = hashFindVal(trackHash, parentTdb->track);
+		if (parentTrack == NULL && parentTdb->parent != NULL)
+		    parentTrack = hashFindVal(trackHash, parentTdb->parent->track);
+
+		if (parentTrack != NULL)
+		    slAddHead(&parentTrack->subtracks, track);
+		else
+		    warn("can't find parentTdb %s in makeDupeTracks", parentTdb->track);
+		}
+	    }
+	}
+    }
+hashFree(&trackHash);
+}
+
+
 void loadTrackHubs(struct track **pTrackList, struct grp **pGrpList)
 /* Load up stuff from data hubs and append to lists. */
 {
 struct trackDb *tdbList = hubCollectTracks(database, pGrpList);
 
 addTdbListToTrackList(tdbList, NULL, pTrackList);
 }
 
 boolean restrictionEnzymesOk()
 /* Check to see if it's OK to do restriction enzymes. */
 {
 return (sqlDatabaseExists("hgFixed") && hTableExists("hgFixed", "cutters") &&
         hTableExists("hgFixed", "rebaseRefs") &&
         hTableExists("hgFixed", "rebaseCompanies"));
 }
@@ -6983,30 +7058,31 @@
 if (wikiTrackEnabled(database, NULL))
     {
     addWikiTrack(&trackList);
     struct sqlConnection *conn = wikiConnect();
     if (sqlTableExists(conn, "variome"))
         addVariomeWikiTrack(&trackList);
     wikiDisconnect(&conn);
     }
 
 struct grp *grpList = NULL;
 if (cartOptionalString(cart, "hgt.trackNameFilter") == NULL)
     { // If a single track was asked for and it is from a hub, then it is already in trackList
     loadTrackHubs(&trackList, &grpList);
     }
 loadCustomTracks(&trackList);
+makeDupeTracks(&trackList);
 groupTracks( &trackList, pGroupList, grpList, vis);
 setSearchedTrackToPackOrFull(trackList);
 boolean hideTracks = cgiOptionalString( "hideTracks") != NULL;
 if (hideTracks)
     changeTrackVis(groupList, NULL, tvHide);    // set all top-level tracks to hide
 
 /* Get visibility values if any from ui. */
 struct hash *superTrackHash = newHash(5);  // cache whether supertrack is hiding tracks or not
 char buffer[4096];
 
 // Check to see if we have a versioned default gene track and let the knownGene 
 // cart variable determine its visibility
 char *defaultGeneTrack = NULL;
 char *knownDb = hdbDefaultKnownDb(database);
 if (differentString(knownDb, database))