c2c65344c6ae672dbc05e7920049803c3fe29874
tdreszer
  Thu Sep 16 12:29:34 2010 -0700
Fixed tdbVisLimitedByAncestry which caused supertrack contained and visibble tracks to appear hidden in findTracks.  Added composite/view vis reshaping based upon subtrack specific vis.
diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index acbbb5a..6644ce4 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -831,32 +831,58 @@
 hashElFreeList(&list);
 }
 
-void cartRemoveLike(struct cart *cart, char *wildCard)
-/* Remove all variable from cart that match wildCard. */
+struct slPair *cartVarsLike(struct cart *cart, char *wildCard)
+/* Return a slPair list of cart vars that match the wildcard */
 {
+struct slPair *cartVars = NULL;
 struct hashEl *el, *elList = hashElListHash(cart->hash);
-
 slSort(&elList, hashElCmp);
 for (el = elList; el != NULL; el = el->next)
     {
     if (wildMatch(wildCard, el->name))
-	cartRemove(cart, el->name);
+        slAddHead(&cartVars,slPairNew(el->name,el->val));
     }
-hashElFreeList(&el);
+hashElFreeList(&elList);
+return cartVars;
 }
 
-void cartRemovePrefix(struct cart *cart, char *prefix)
-/* Remove variables with given prefix from cart. */
+struct slPair *cartVarsWithPrefix(struct cart *cart, char *prefix)
+/* Return a slPair list of cart vars that begin with prefix */
 {
+struct slPair *cartVars = NULL;
 struct hashEl *el, *elList = hashElListHash(cart->hash);
-
 slSort(&elList, hashElCmp);
 for (el = elList; el != NULL; el = el->next)
     {
     if (startsWith(prefix, el->name))
-	cartRemove(cart, el->name);
+        slAddHead(&cartVars,slPairNew(el->name,el->val));
+    }
+hashElFreeList(&elList);
+return cartVars;
+}
+
+void cartRemoveLike(struct cart *cart, char *wildCard)
+/* Remove all variable from cart that match wildCard. */
+{
+struct slPair *cartVars = cartVarsLike(cart,wildCard);
+while(cartVars != NULL)
+    {
+    struct slPair *cartVar = slPopHead(&cartVars);
+    cartRemove(cart, cartVar->name);
+    freeMem(cartVar);
+    }
+}
+
+void cartRemovePrefix(struct cart *cart, char *prefix)
+/* Remove variables with given prefix from cart. */
+{
+struct slPair *cartVars = cartVarsWithPrefix(cart,prefix);
+while(cartVars != NULL)
+    {
+    struct slPair *cartVar = slPopHead(&cartVars);
+    cartRemove(cart, cartVar->name);
+    freeMem(cartVar);
     }
-hashElFreeList(&el);
 }
 
 boolean cartVarExists(struct cart *cart, char *var)
@@ -1983,45 +2009,15 @@
 return (differentString(newValue,oldValue));
 }
 
-struct slRef *cartNamesLike(struct cart *cart, char *wildCard)
-/* Returns reference list of all variable names that match wildCard. */
-{
-struct hashEl *el, *elList = hashElListHash(cart->hash);
-struct slRef *matches = NULL;
-
-for (el = elList; el != NULL; el = el->next)
-    {
-    if (wildMatch(wildCard, el->name))
-        slAddHead(&matches,slRefNew(el->name));
-    }
-hashElFreeList(&elList);
-return matches;
-}
-
-struct slRef *cartNamesPrefixedBy(struct cart *cart, char *prefix)
-/* Returns reference list of all variable names with given prefix. */
-{
-struct hashEl *el, *elList = hashElListHash(cart->hash);
-struct slRef *matches = NULL;
-
-for (el = elList; el != NULL; el = el->next)
-    {
-    if (startsWith(prefix, el->name))
-        slAddHead(&matches,slRefNew(el->name));
-    }
-hashElFreeList(&elList);
-return matches;
-}
-
 int cartNamesPruneChanged(struct cart *newCart,struct hash *oldVars,
-                          struct slRef **cartNames,boolean ignoreRemoved,boolean unChanged)
+                          struct slPair **cartNames,boolean ignoreRemoved,boolean unChanged)
 /* Prunes a list of cartNames if the settings have changed between new and old cart.
    Returns pruned count */
 {
 int pruned = 0;
-struct slRef *oldList = *cartNames;
-struct slRef *newList = NULL;
-struct slRef *oneName = NULL;
+struct slPair *oldList = *cartNames;
+struct slPair *newList = NULL;
+struct slPair *oneName = NULL;
 while ((oneName = slPopHead(&oldList)) != NULL)
     {
     boolean thisOneChanged = cartValueHasChanged(newCart,oldVars,oneName->val,ignoreRemoved,TRUE);
@@ -2058,6 +2054,215 @@
 return removed;
 }
 
+// Shaping composite vis by subtrack specific vis comes in 3 flavors:
+// Simple) No shaping.  Subtrack specific vis overrides composite/view level but does not alter it
+// Plan A) When composite is in default settings only, then composite/vis is shaped to reflect current subtrack vis
+// Plan B) Whenever there is subtrack level vis, the composite and view vis are shaped to show maximum subtrack vis,
+//         while subtracks with inherited vis may be given subtrack specific vis to return them to that state
+#define COMPOSITE_VIS_SHAPING_PLAN_A
+//#define COMPOSITE_VIS_SHAPING_PLAN_B
+
+#if defined(COMPOSITE_VIS_SHAPING_PLAN_A) || defined(COMPOSITE_VIS_SHAPING_PLAN_B)
+static int cartTdbParentShapeVis(struct cart *cart,struct trackDb *parent,char *view,struct slRef *refSubtracks,struct slPair *subVisVars,boolean compositeAtDefault)
+// This shapes one level of vis (view or composite) based upon subtrack specific visibility.  Returns count of subtracks affected
+{
+int count=0;
+struct slPair *subVisVar = NULL;
+struct trackDb *subtrack = NULL;
+char setting[512];
+if (view != NULL)
+    safef(setting,sizeof(setting),"%s.%s.vis",parent->parent->track,view);
+else
+    safef(setting,sizeof(setting),"%s",parent->track);
+
+enum trackVisibility vis = tvHide;  // Looking for max vis of subtrack specific
+enum trackVisibility visOrig = hTvFromString(cartUsualString(cart,setting,hStringFromTv(parent->visibility)));
+if (!compositeAtDefault)
+    vis = visOrig; // Default view vis to current vis
+for(subVisVar=subVisVars;subVisVar!=NULL;subVisVar=subVisVar->next)
+    {
+    if (endsWith(subVisVar->name,"_sel"))
+        {
+        subtrack = subVisVar->val;
+        if (parent != subtrack->parent) // This should be true whether at view level or composite level,
+            continue;                   // since composite level call only happens composite has no views
+
+        char *cartVis = cartOptionalString(cart,subtrack->track);
+        assert(cartVis != NULL); // Otherwise it wouldn't be in subVisVar
+        enum trackVisibility visSub = hTvFromString(cartVis);
+        if (tvCompare(vis, visSub) >= 0)
+            vis = visSub; // vis will wind up with setting of highest vis subtrack
+        }
+    }
+if (vis != visOrig)
+    {
+    cartSetString(cart,setting,hStringFromTv(vis));
+    //warn("Set %s to %s",(view?view:parent->track),hStringFromTv(vis));
+
+    // Now set all subtracks that inherit vis back to visOrig
+    struct slRef *refSub;
+    for(refSub = refSubtracks;refSub != NULL;refSub = refSub->next)
+        {
+        subtrack = refSub->val;
+        if (parent != subtrack->parent) // This should work whether at view level or composite level,
+            continue;                   // since composite level call only happens composite has no views
+
+        if (!slPairFind(subVisVars, subtrack->track))   // if the subtrack doesn't have individual vis AND...
+            {
+            // FIXME problem is fourState gets cached
+            int fourState = subtrackFourStateChecked(subtrack,cart);
+            if (fourStateChecked(fourState))            // subtrack is checked
+                {
+                if (compositeAtDefault || visOrig == tvHide)
+                    subtrackFourStateCheckedSet(subtrack, cart,FALSE,fourStateEnabled(fourState));
+                else
+                    cartSetString(cart,subtrack->track,hStringFromTv(visOrig));
+                count++;
+                }
+            }
+        }
+    //warn("Altered %d subtrack(s) for %s",count,(view?view:parent->track));
+
+    if (tdbIsCompositeView(parent))
+        {
+        cartSetString(cart,parent->parent->track,"full");    // Now set composite to full.
+        //warn("Set composite %s to full",tdbComposite->track);
+        }
+    }
+return count;
+}
+
+static boolean cartVarsAllFoundForTdb(struct cart *cart,struct slPair *subVisVars,struct trackDb *tdb)
+{
+struct slPair *cartVar,*cartVars = cartVarsWithPrefix(cart,tdb->track);
+if (cartVars != NULL)
+    {
+    for (cartVar = cartVars; cartVar != NULL; cartVar = cartVar->next)
+        {
+        if (tdbIsCompositeView(tdb) || !slPairFind(subVisVars, cartVar->name)) // subVisVars does not contain anything prefixed by view!
+            {
+            // NOTE: This is less than ideal!  Composites (not memebers of superTracks) are getting their cart vis set on hgTracks:config page!
+            if (tdbIsComposite(tdb)
+            &&  sameString(cartVar->name,tdb->track)
+            &&  sameString((char *)cartVar->val,hStringFromTv(tdb->visibility)) )
+                continue;
+
+            slFreeList(&cartVars);
+            return FALSE; // Any view cart vars means non-default so do not "shape" composite
+            }
+        }
+    slFreeList(&cartVars);
+    }
+return TRUE;
+}
+#endif/// defined(COMPOSITE_VIS_SHAPING_PLAN_A) || defined(COMPOSITE_VIS_SHAPING_PLAN_B)
+
+boolean cartTdbTreeMatchSubtrackVis(struct cart *cart,struct trackDb *tdbComposite)
+/* When subtrack vis is set via findTracks, and composite has no cart settings,
+   then "shape" composite to match found */
+{
+#if !defined(COMPOSITE_VIS_SHAPING_PLAN_A) && !defined(COMPOSITE_VIS_SHAPING_PLAN_B)
+    return FALSE;  // Don't do any shaping
+#else/// if defined(COMPOSITE_VIS_SHAPING_PLAN_A) || defined(COMPOSITE_VIS_SHAPING_PLAN_B)
+
+// First look for subtrack vis
+char setting[512];
+struct trackDb *subtrack = NULL;
+struct slPair *subVisVar, *subVisVars = NULL;
+struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendantLeaves(tdbComposite->subtracks);
+for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
+    {
+    subtrack = tdbRef->val;
+    char *val=cartOptionalString(cart,subtrack->track);
+    if (val && differentString(val,"hide"))  // NOTE should we include hide?
+        {
+        subVisVar = slPairNew(subtrack->track,val); // subtrack has sub level vis
+        slAddHead(&subVisVars,subVisVar);
+        // Add the "_sel" setting which should also exist.  Point it to subtrack
+        safef(setting,sizeof(setting),"%s_sel",subtrack->track);
+        subVisVar = slPairNew(setting,subtrack);
+        slAddHead(&subVisVars,subVisVar);
+        }
+    }
+if (slCount(subVisVars) == 0)
+    {
+    //warn("No subtrack vis found.");
+    slFreeList(&tdbRefList);
+    return FALSE;
+    }
+
+// Next look for any cart settings other than subtrack vis/sel
+boolean compositeAtDefault = TRUE;
+compositeAtDefault = cartVarsAllFoundForTdb(cart,subVisVars,tdbComposite);
+#ifndef COMPOSITE_VIS_SHAPING_PLAN_B
+if (!compositeAtDefault)
+    {
+    slFreeList(&tdbRefList);
+    slFreeList(&subVisVars);
+    return FALSE; // Any view cart vars means non-default so do not "shape" composite
+    }
+#endif///ndef COMPOSITE_VIS_SHAPING_PLAN_B
+
+// What about view level settings?
+struct trackDb *tdbView = tdbComposite->subtracks;
+boolean hasViews = FALSE;
+if (tdbIsCompositeView(tdbView))
+    {
+    if (compositeAtDefault)
+        {
+        for( ;tdbView != NULL; tdbView = tdbView->next )
+            {
+            compositeAtDefault = cartVarsAllFoundForTdb(cart,subVisVars,tdbView);
+            #ifndef COMPOSITE_VIS_SHAPING_PLAN_B
+            if (!compositeAtDefault)
+                {
+                slFreeList(&tdbRefList);
+                slFreeList(&subVisVars);
+                return FALSE; // Any view cart vars means non-default so do not "shape" composite
+                }
+            #endif///ndef COMPOSITE_VIS_SHAPING_PLAN_B
+            }
+        }
+    hasViews = TRUE;
+    }
+
+// How about subtrack level settings?  Assume that compositePrefix caught them? If views then YES
+if (compositeAtDefault && !hasViews)
+    {
+    for(tdbRef = tdbRefList;tdbRef != NULL; tdbRef = tdbRef->next )
+        {
+        compositeAtDefault = cartVarsAllFoundForTdb(cart,subVisVars,subtrack);
+        #ifndef COMPOSITE_VIS_SHAPING_PLAN_B
+        if (!compositeAtDefault)
+            {
+            slFreeList(&tdbRefList);
+            slFreeList(&subVisVars);
+            return FALSE; // Any view cart vars means non-default so do not "shape" composite
+            }
+        #endif///ndef COMPOSITE_VIS_SHAPING_PLAN_B
+        }
+    }
+
+// Now shape views and composite to match subtrack specific visibility
+    int count = 0;
+if (hasViews)
+    {
+    for(tdbView = tdbComposite->subtracks;tdbView != NULL; tdbView = tdbView->next )
+        {
+        char *view = trackDbSetting(tdbView,"view");
+        assert(view != NULL);
+        count += cartTdbParentShapeVis(cart,tdbView,view,tdbRefList,subVisVars,compositeAtDefault);
+        }
+    }
+else // If no views then composite is not set to fuul but to max of subtracks
+    count = cartTdbParentShapeVis(cart,tdbComposite,NULL,tdbRefList,subVisVars,compositeAtDefault);
+//warn("Altered %d subtrack(s)",count);
+
+slFreeList(&tdbRefList);
+slFreeList(&subVisVars);
+return TRUE;
+#endif/// defined(COMPOSITE_VIS_SHAPING_PLAN_A) || defined(COMPOSITE_VIS_SHAPING_PLAN_B)
+}
 
 boolean cartTdbTreeCleanupOverrides(struct trackDb *tdb,struct cart *newCart,struct hash *oldVars)
 /* When composite/view settings changes, remove subtrack specific settings
@@ -2069,7 +2274,7 @@
 // vis is a special additive case! composite or view level changes then remove subtrack vis
 boolean compositeVisChanged = cartValueHasChanged(newCart,oldVars,tdb->track,TRUE,TRUE);
 struct trackDb *tdbView = NULL;
-struct slRef *oneName = NULL;
+struct slPair *oneName = NULL;
 char * var = NULL;
 int clensed = 0;
 
@@ -2088,14 +2293,14 @@
 safef(setting,sizeof(setting),"%s.",tdb->track);
 char * view = NULL;
 boolean hasViews = FALSE;
-struct slRef *changedSettings = cartNamesPrefixedBy(newCart, setting);
+struct slPair *changedSettings = cartVarsWithPrefix(newCart, setting);
 for (tdbView = tdb->subtracks;tdbView != NULL; tdbView = tdbView->next)
     {
     if (!tdbIsView(tdbView,&view))
         break;
     hasViews = TRUE;
     safef(setting,sizeof(setting),"%s.",tdbView->track);
-    struct slRef *changeViewSettings = cartNamesPrefixedBy(newCart, setting);
+    struct slPair *changeViewSettings = cartVarsWithPrefix(newCart, setting);
     changedSettings = slCat(changedSettings, changeViewSettings);
     }
 if (changedSettings == NULL && !compositeVisChanged)
@@ -2125,7 +2330,7 @@
         safef(setting,   sizeof(setting),"%s.%s.",tdb->track,view); // unfortunatly setting name could be wgEncodeBroadHistone.Sig.???r
         char settingAlt[512];
         safef(settingAlt,sizeof(settingAlt),"%s.",tdbView->track);  // or wgEncodeBroadHistoneViewSig.???
-        struct slRef *leftOvers = NULL;
+        struct slPair *leftOvers = NULL;
         // Walk through settings that match this view
         while ((oneName = slPopHead(&changedSettings)) != NULL)
             {