0f5736b164087c5cc8a365d0cba96977f3773d9e
tdreszer
  Wed Dec 15 15:13:36 2010 -0800
Hopefully top-down and bottom-up clean-up of composite cart vars now works.  Top-down first, but does not remove new subtrack-level vis
diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 64f5a20..834f0de 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -1982,30 +1982,54 @@
 boolean vis = (suffix == NULL || *suffix == '\0');
 struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendants(skipParent?tdb->subtracks:tdb);
 for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
     {
     struct trackDb *descendentTdb = tdbRef->val;
     char settingName[512];  // wgEncodeOpenChromChip.Peaks.vis
     if (vis)
         safef(settingName,sizeof(settingName),"%s",descendentTdb->track);
     else
         safef(settingName,sizeof(settingName),"%s.%s",descendentTdb->track,suffix);
     removed += cartRemoveAndCount(cart,settingName);
     }
 return removed;
 }
 
+static int cartRemoveOldFromTdbTree(struct cart *newCart,struct hash *oldVars,struct trackDb *tdb,char *suffix,char *parentVal,boolean skipParent)
+/* Removes a 'trackName.suffix' from all tdb descendents (but not parent), BUT ONLY IF OLD or same as parentVal.
+   If suffix NULL then removes 'trackName' which holds visibility */
+{
+int removed = 0;
+boolean vis = (suffix == NULL || *suffix == '\0');
+struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendants(skipParent?tdb->subtracks:tdb);
+for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
+    {
+    struct trackDb *descendentTdb = tdbRef->val;
+    char settingName[512];  // wgEncodeOpenChromChip.Peaks.vis
+    if (vis)
+        safef(settingName,sizeof(settingName),"%s",descendentTdb->track);
+    else
+        safef(settingName,sizeof(settingName),"%s.%s",descendentTdb->track,suffix);
+    char *newVal = cartOptionalString(newCart,settingName);
+    if (    newVal    != NULL
+    && (   (parentVal != NULL && sameString(newVal,parentVal))
+        || (FALSE == cartValueHasChanged(newCart,oldVars,settingName,TRUE,FALSE))))
+        removed += cartRemoveAndCount(newCart,settingName);
+    }
+return removed;
+}
+
 static boolean cartTdbOverrideSuperTracks(struct cart *cart,struct trackDb *tdb,boolean ifJustSelected)
 /* When when the child of a hidden supertrack is foudn and selected, then shape the supertrack accordingly
    Returns TRUE if any cart changes are made */
 {
 // This is only pertinent to supertrack children just turned on
 if (!tdbIsSuperTrackChild(tdb))
     return FALSE;
 
 char setting[512];
 
 // Must be from having just selected the track in findTracks.  This will carry with it the "_sel" setting.
 if (ifJustSelected)
     {
     safef(setting,sizeof(setting),"%s_sel",tdb->track);
     if (!cartVarExists(cart,setting))
@@ -2106,49 +2130,56 @@
         {
         cartSetString(cart,setting,hStringFromTv(visMax));    // Set this explicitly.  The visOrig may be inherited!
         countVisChanged++;
         if (visOrig == tvHide && tdbIsSuperTrackChild(parent))
             cartTdbOverrideSuperTracks(cart,parent,FALSE);      // deal with superTrack vis! cleanup
         }
 
     // Now set all subtracks that inherit vis back to visOrig
     for(subtrack = parent->subtracks;subtrack != NULL;subtrack = subtrack->next)
         {
         int fourState = subtrackFourStateChecked(subtrack,cart);
         if (!fourStateChecked(fourState))
             cartRemove(cart,subtrack->track);  // Remove subtrack level vis if it isn't even checked just in case
         else  // subtrack is checked (should include subtrack level vis)
             {
-            if (!hashFindVal(subVisHash, subtrack->track))   // if the subtrack doesn't have individual vis AND...
+            char *visFromHash = hashFindVal(subVisHash, subtrack->track);
+            if (tdbIsMultiTrack(parent))
+                cartRemove(cart,subtrack->track);  // MultiTrack vis is ALWAYS inherited vis and non-selected should not have vis
+            if (visFromHash == NULL)   // if the subtrack doesn't have individual vis AND...
                 {
                 if (reshapeFully || visOrig == tvHide)
                     {
                     subtrackFourStateCheckedSet(subtrack, cart,FALSE,fourStateEnabled(fourState)); // uncheck
                     cartRemove(cart,subtrack->track);  // Remove it if it exists, just in case
                     countUnchecked++;
                     }
                 else if (visOrig != tvHide)
                     {
-                    if (tdbIsMultiTrack(parent))
-                        cartRemove(cart,subtrack->track);  // MultiTrack vis is ALWAYS inherited
-                    else
                         cartSetString(cart,subtrack->track,hStringFromTv(visOrig));
                     countVisChanged++;
                     }
                 }
-            else if (tdbIsMultiTrack(parent))
-                cartRemove(cart,subtrack->track);  // MultiTrack vis is ALWAYS inherited vis and non-selected should not have vis
+            else // This subtrack has explicit vis
+                {
+                enum trackVisibility vis = hTvFromString(visFromHash);
+                if (vis == visMax)
+                    {
+                    cartRemove(cart,subtrack->track);  // Remove vis which should now be inherited
+                    countVisChanged++;
+                    }
+                }
             }
         }
     }
 else if (tdbIsMultiTrack(parent))
     {
     // MultiTrack vis is ALWAYS inherited vis so remove any subtrack specific vis
     struct hashCookie brownie = hashFirst(subVisHash);
     struct hashEl* cartVar = NULL;
     while ((cartVar = hashNext(&brownie)) != NULL)
         {
         if (!endsWith(cartVar->name,"_sel"))
             cartRemove(cart,cartVar->name);
         }
     }
 if (countUnchecked + countVisChanged)
@@ -2306,60 +2337,62 @@
             {
             if(startsWith(setting,oneName->name))
                 suffix = oneName->name + strlen(setting);
             else if(startsWith(settingAlt,oneName->name))
                 suffix = oneName->name + strlen(settingAlt);
             else
                 {
                 slAddHead(&leftOvers,oneName);
                 continue;
                 }
 
             if (sameString(suffix,"vis"))
                 {
                 viewVisChanged = TRUE;
                 }
-            else if (cartRemoveFromTdbTree(newCart,tdbView,suffix,TRUE) > 0)
+            else if (cartRemoveOldFromTdbTree(newCart,oldVars,tdbView,suffix,oneName->val,TRUE) > 0)
                     clensed++;
 
             freeMem(oneName);
             }
         if (viewVisChanged)
             {
             // If just created and if vis is the same as tdb default then vis has not changed
             safef(setting,sizeof(setting),"%s.%s.vis",tdb->track,view);
             char *cartVis = cartOptionalString(newCart,setting);
             char *oldValue = hashFindVal(oldVars,setting);
             if (cartVis && oldValue == NULL && hTvFromString(cartVis) != tdbView->visibility)
                 viewVisChanged = FALSE;
             }
 
         if  (containerVisChanged || viewVisChanged)
             { // vis is a special additive case!
             WARN("Removing subtrack vis for %s.%s",tdb->track,view);
-            if (cartRemoveFromTdbTree(newCart,tdbView,NULL,TRUE) > 0)
+            char *viewVis = hStringFromTv(tdbVisLimitedByAncestry(newCart, tdbView, FALSE));
+            if (cartRemoveOldFromTdbTree(newCart,oldVars,tdbView,NULL,viewVis,TRUE) > 0)
                 clensed++;
             }
         changedSettings = leftOvers;
         }
     }
 
 // Now deal with anything remaining at the container level
 while ((oneName = slPopHead(&changedSettings)) != NULL)
     {
     suffix = oneName->name + strlen(tdb->track) + 1;
-    if(cartRemoveFromTdbTree(newCart,tdb,suffix,TRUE) > 0)
+    if (cartRemoveOldFromTdbTree(newCart,oldVars,tdb,suffix,oneName->val,TRUE) > 0)
         clensed++;
     freeMem(oneName);
     }
 if  (containerVisChanged && !hasViews)
     { // vis is a special additive case!
-    if (cartRemoveFromTdbTree(newCart,tdb,NULL,TRUE) > 0)
+    char *vis = hStringFromTv(tdbVisLimitedByAncestry(newCart, tdb, FALSE));
+    if (cartRemoveOldFromTdbTree(newCart,oldVars,tdb,NULL,vis,TRUE) > 0)
         clensed++;
     }
 
 anythingChanged = (anythingChanged || (clensed > 0));
 return anythingChanged;
 }