c0b183c96763a6ebf2c050e82859373309a2befe angie Fri Oct 31 17:19:56 2014 -0700 When lookupPosition() returns false (multiple search results), thesubsequent call to doMainPage(conn, TRUE) was causing a popWarnHandler underflow errAbort because doMainPage ends with an htmlClose (which btw invokes popWarnHandler three times: one directly, once in cartWebEnd and once in webEnd). The symptom was that changes made to the main page form before looking up a term that returned multiple results were lost because the underflow errAbort prevented the cart from being saved. The solution is to not use doMainPage(conn, TRUE) but instead to call mainPageAfterOpen enclosed by push and pop of web warn/error handlers. Since doMainPage(conn, TRUE) caused trouble that can be avoided by calling mainPageAfterOpen, I removed the option. I also removed dead code doLookupPosition; dispatch is called only when lookupPosition() has already returned a single match, so the work is already done and it will default to the main page anyway. refs #12557 diff --git src/hg/hgTables/compositeTrack.c src/hg/hgTables/compositeTrack.c index 2169bfe..bd6713a 100644 --- src/hg/hgTables/compositeTrack.c +++ src/hg/hgTables/compositeTrack.c @@ -1,300 +1,300 @@ /* compositeTrack -- handle composite tracks / subtrack merge. */ /* Copyright (C) 2013 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include "common.h" #include "linefile.h" #include "hash.h" #include "portable.h" #include "cheapcgi.h" #include "cart.h" #include "jksql.h" #include "trackDb.h" #include "bed.h" #include "hdb.h" #include "hui.h" #include "hgTables.h" /* We keep two copies of variables, so that we can * cancel out of the page. */ static char *curVars[] = {hgtaSubtrackMergePrimary, hgtaSubtrackMergeOp, hgtaSubtrackMergeMoreThreshold, hgtaSubtrackMergeLessThreshold, hgtaSubtrackMergeWigOp, hgtaSubtrackMergeRequireAll, hgtaSubtrackMergeUseMinScore, hgtaSubtrackMergeMinScore, }; static char *nextVars[] = {hgtaNextSubtrackMergePrimary, hgtaNextSubtrackMergeOp, hgtaNextSubtrackMergeMoreThreshold, hgtaNextSubtrackMergeLessThreshold, hgtaNextSubtrackMergeWigOp, hgtaNextSubtrackMergeRequireAll, hgtaNextSubtrackMergeUseMinScore, hgtaNextSubtrackMergeMinScore, }; boolean anySubtrackMerge(char *db, char *table) /* Return TRUE if a subtrack merge has been specified on db.table. */ { char *smp = cartOptionalString(cart, hgtaSubtrackMergePrimary); if (smp == NULL) return FALSE; else { char *dbTable = getDbTable(db, table); boolean curTableHasMerge = sameString(smp, dbTable); freez(&dbTable); return curTableHasMerge; } } boolean subtrackMergeIsBpWise() /* Return TRUE if the subtrack merge operation is base pair-wise. */ { char *op = cartUsualString(cart, hgtaSubtrackMergeOp, "any"); return (sameString(op, "and") || sameString(op, "or")); } boolean isSubtrackMerged(char *tableName) /* Return true if tableName has been selected for subtrack merge. */ { char option[128]; safef(option, sizeof(option), "%s_sel", tableName); return cartUsualBoolean(cart, option, FALSE); } static void makeWigOpButton(char *val, char *selVal) /* Make merge-wiggle-op radio button. */ { cgiMakeRadioButton(hgtaNextSubtrackMergeWigOp, val, sameString(val, selVal)); } static void showWiggleMergeOptions() /* Show subtrack merge operation options for wiggle/bedGraph tables. */ { char *setting = cartUsualString(cart, hgtaNextSubtrackMergeWigOp, "average"); makeWigOpButton("average", setting); printf("Average (at each position) of all selected subtracks' scores
\n"); makeWigOpButton("sum", setting); printf("Sum (at each position) of all selected subtracks' scores
\n"); makeWigOpButton("product", setting); printf("Product (at each position) of all selected subtracks' scores
\n"); makeWigOpButton("min", setting); printf("Minimum (at each position) of all selected subtracks' scores
\n"); makeWigOpButton("max", setting); printf("Maximum (at each position) of all selected subtracks' scores

\n"); cgiMakeCheckBox(hgtaNextSubtrackMergeRequireAll, cartUsualBoolean(cart, hgtaSubtrackMergeRequireAll, FALSE)); printf("Discard scores for positions at which one or more selected subtracks " "have no data.
\n"); cgiMakeCheckBox(hgtaNextSubtrackMergeUseMinScore, cartUsualBoolean(cart, hgtaSubtrackMergeUseMinScore, FALSE)); printf("Discard scores less than \n"); setting = cartCgiUsualString(cart, hgtaNextSubtrackMergeMinScore, "0.0"); cgiMakeTextVar(hgtaNextSubtrackMergeMinScore, setting, 5); printf(" after performing the above operation.

\n"); } static void makeOpButton(char *val, char *selVal) /* Make merge-bed-op radio button. */ { cgiMakeRadioButton(hgtaNextSubtrackMergeOp, val, sameString(val, selVal)); } static void showBedMergeOptions() /* Show subtrack merge operation options for tables that are distilled * to BED (not wiggle/bedGraph). */ { char *op = cartUsualString(cart, hgtaNextSubtrackMergeOp, "any"); char *setting = NULL; hPrintf("These combinations will maintain the gene/alignment structure " "(if any) of %s:

\n", curTable); makeOpButton("any", op); printf("All %s records that have any overlap with any other selected subtrack
\n", curTable); makeOpButton("none", op); printf("All %s records that have no overlap with any other selected subtrack
\n", curTable); makeOpButton("more", op); printf("All %s records that have at least ", curTable); setting = cartCgiUsualString(cart, hgtaNextSubtrackMergeMoreThreshold, "80"); cgiMakeTextVar(hgtaNextSubtrackMergeMoreThreshold, setting, 3); printf(" %% overlap with any other selected subtrack
\n"); makeOpButton("less", op); printf("All %s records that have at most ", curTable); setting = cartCgiUsualString(cart, hgtaNextSubtrackMergeLessThreshold, "80"); cgiMakeTextVar(hgtaNextSubtrackMergeLessThreshold, setting, 3); printf(" %% overlap with any other selected subtrack
\n"); makeOpButton("cat", op); printf("All %s records, as well as all records from all other selected subtracks

\n", curTable); printf("These combinations will discard the gene/alignment structure (if any) " "of %s and produce a simple list of position ranges.

\n", curTable); makeOpButton("and", op); printf("Base-pair-wise intersection (AND) of %s and other selected subtracks
\n", curTable); makeOpButton("or", op); printf("Base-pair-wise union (OR) of %s and other selected subtracks

\n", curTable); } void doSubtrackMergeMore(struct sqlConnection *conn) /* Respond to subtrack merge create/edit button */ { char *dbTable = getDbTable(database, curTable); htmlOpen("Merge subtracks of %s (%s)", curTrack->table, curTrack->longLabel); hPrintf("

\n", cartUsualString(cart, "formMethod", "POST")); cartSaveSession(cart); /* Currently selected subtrack table will be the primary subtrack in the * merge. */ cgiMakeHiddenVar(hgtaNextSubtrackMergePrimary, dbTable); hPrintf("

Select a subset of subtracks to merge:

\n"); hCompositeUi(database, cart, curTrack, curTable, hgtaDoSubtrackMergePage, "mainForm"); hPrintf("

Select a merge operation:

\n"); struct trackDb *primary = subTdbFind(curTrack,curTable); if (isWiggle(database, curTable) || isBedGraph(curTable) || isBigWigTable(curTable)) showWiggleMergeOptions(); else showBedMergeOptions(); hPrintf("If a filter is specified on the main Table Browser page, it will " "be applied only to %s, not to any other selected subtrack. ", primary->longLabel); hPrintf("If an intersection is specified on the main page, it will be applied " "to the result of this merge.

\n"); hPrintf("

\n"); cgiMakeButton(hgtaDoSubtrackMergeSubmit, "submit"); hPrintf(" "); cgiMakeButton(hgtaDoMainPage, "cancel"); hPrintf("

\n"); htmlClose(); } char *describeSubtrackMerge(char *linePrefix) /* Return a multi-line string that describes the specified subtrack merge, * with each line beginning with linePrefix. */ { struct dyString *dy = dyStringNew(512); struct trackDb *primary = subTdbFind(curTrack,curTable), *tdb = NULL; dyStringAppend(dy, linePrefix); dyStringPrintf(dy, "Subtrack merge, primary table = %s (%s)\n", curTable, primary->longLabel); dyStringAppend(dy, linePrefix); dyStringPrintf(dy, "Subtrack merge operation: "); if (isWiggle(database, curTable) || isBedGraph(curTable) || isBigWigTable(curTable)) { char *op = cartString(cart, hgtaSubtrackMergeWigOp); dyStringPrintf(dy, "%s of %s and selected subtracks:\n", op, curTable); } else { char *op = cartString(cart, hgtaSubtrackMergeOp); if (sameString(op, "any")) dyStringPrintf(dy, "All %s records that have any overlap with " "any other selected subtrack:\n", curTable); else if (sameString(op, "none")) dyStringPrintf(dy, "All %s records that have no overlap with " "any other selected subtrack:\n", curTable); else if (sameString(op, "more")) { dyStringPrintf(dy, "All %s records that have at least %s ", curTable, cartString(cart, hgtaNextSubtrackMergeMoreThreshold)); dyStringPrintf(dy, " %% overlap with any other selected subtrack:\n"); } else if (sameString(op, "less")) { dyStringPrintf(dy, "All %s records that have at most %s ", curTable, cartString(cart, hgtaNextSubtrackMergeLessThreshold)); dyStringPrintf(dy, " %% overlap with any other selected subtrack:\n"); } else if (sameString(op, "cat")) dyStringPrintf(dy, "All %s records, as well as all records from " "all other selected subtracks:\n", curTable); else if (sameString(op, "and")) dyStringPrintf(dy, "Base-pair-wise intersection (AND) of %s and " "other selected subtracks:\n", curTable); else if (sameString(op, "or")) dyStringPrintf(dy, "Base-pair-wise union (OR) of %s and other " "selected subtracks:\n", curTable); else errAbort("describeSubtrackMerge: unrecognized op %s", op); } struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendantLeaves(curTrack->subtracks); for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) { tdb = tdbRef->val; if (!sameString(tdb->table, curTable) && isSubtrackMerged(tdb->table) && sameString(tdb->type, primary->type)) { dyStringAppend(dy, linePrefix); dyStringPrintf(dy, " %s (%s)\n", tdb->table, tdb->longLabel); } } return dyStringCannibalize(&dy); } static void copyCartVars(struct cart *cart, char **source, char **dest, int count) /* Copy from source to dest (arrays of cart variable names). */ { int i; for (i=0; i