7c96305a8cc177ad7792386ab9978f66fc82e0a2 braney Thu Nov 8 14:26:53 2018 -0800 make filterBy and labels be smarter about being configured at the view level diff --git src/hg/lib/hui.c src/hg/lib/hui.c index d9bb321..8c50b44 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -3605,31 +3605,31 @@ if (val == filterBy->slValues) // First one filterBy->valueAndLabel = TRUE; if (filterBy->valueAndLabel == FALSE) errAbort("filterBy values either all have labels (as value|label) " "or none do."); *chipper++ = 0; // The label is found inside filters->svValues as the next string strSwapChar(chipper,'_',' '); // Title does not have underscores } else if (filterBy->valueAndLabel) errAbort("filterBy values either all have labels in form of value|label " "or none do."); } } } -filterBy_t *buildFilterBy(struct trackDb *tdb, struct cart *cart, struct asObject *as, char *filterName) +filterBy_t *buildFilterBy(struct trackDb *tdb, struct cart *cart, struct asObject *as, char *filterName, char *name) /* Build a filterBy_t structure from a FilterValues statement. */ { char *setting = trackDbSetting(tdb, filterName); char *value = cartUsualStringClosestToHome(cart, tdb, FALSE, filterName, setting); char *field = cloneString(filterName); int ix = strlen(field) - strlen(FILTER_VALUES_NAME); assert(ix > 0); field[ix] = '\0'; filterBy_t *filterBy; AllocVar(filterBy); filterBy->column = field; filterBy->title = field; /// title should come from AS file, or trackDb variable struct asColumn *asCol = asColumnFind(as, field); if (asCol != NULL) @@ -3640,57 +3640,56 @@ if (cart != NULL) { char suffix[256]; safef(suffix, sizeof(suffix), "%s.%s", "filterBy", filterBy->column); boolean parentLevel = isNameAtParentLevel(tdb,tdb->track); if (cartLookUpVariableClosestToHome(cart,tdb,parentLevel,suffix,&(filterBy->htmlName))) { filterBy->slChoices = cartOptionalSlNameList(cart,filterBy->htmlName); freeMem(filterBy->htmlName); } } // Note: cannot use found name above because that may be at a higher (composite/view) level int len = strlen(tdb->track) + strlen(filterBy->column) + 15; filterBy->htmlName = needMem(len); -safef(filterBy->htmlName, len, "%s.%s.%s", tdb->track,"filterBy",filterBy->column); -freeMem(setting); +safef(filterBy->htmlName, len, "%s.%s.%s", name,"filterBy",filterBy->column); return filterBy; } -filterBy_t *filterByValues(struct trackDb *tdb, struct cart *cart, struct slName *filterValues) +filterBy_t *filterByValues(struct trackDb *tdb, struct cart *cart, struct slName *filterValues, char *name) /* Build a filterBy_t list from tdb variables of the form *FilterValues */ { struct asObject *as = asForTdb(NULL, tdb); filterBy_t *filterByList = NULL, *filter; struct slName *fieldFilter; while ((fieldFilter = slPopHead(&filterValues)) != NULL) { - if ((filter = buildFilterBy(tdb, cart, as, fieldFilter->name)) != NULL) + if ((filter = buildFilterBy(tdb, cart, as, fieldFilter->name, name)) != NULL) slAddHead(&filterByList, filter); } return filterByList; } filterBy_t *filterBySetGetGuts(struct trackDb *tdb, struct cart *cart, char *name, char *subName, char *settingName) // Gets one or more "filterBy" settings (ClosestToHome). returns NULL if not found { // first check to see if this tdb is using "new" FilterValues cart variables struct slName *filterValues = trackDbSettingsWildMatch(tdb, FILTER_VALUES_WILDCARD); if (filterValues) - return filterByValues(tdb, cart, filterValues); + return filterByValues(tdb, cart, filterValues, name); filterBy_t *filterBySet = NULL; char *setting = trackDbSettingClosestToHome(tdb, settingName); if(setting == NULL) return NULL; if ( name == NULL ) name = tdb->track; setting = cloneString(setting); char *filters[10]; // multiple filterBys are delimited by space but spaces inside filter can be protected "by quotes" int filterCount = chopByWhiteRespectDoubleQuotes(setting, filters, ArraySize(filters)); int ix; for (ix=0;ix%s\n",label); } void filterBySetCfgUiGuts(struct cart *cart, struct trackDb *tdb, filterBy_t *filterBySet, boolean onOneLine, - char *filterTypeTitle, char *selectIdPrefix, char *allLabel) + char *filterTypeTitle, char *selectIdPrefix, char *allLabel, char *prefix) // Does the UI for a list of filterBy structure for either filterBy or highlightBy controls { if (filterBySet == NULL) return; #define FILTERBY_HELP_LINK "help" int count = slCount(filterBySet); if (count == 1) puts(""); else printf("%s items by: (select multiple categories and items - %s)" "
\n",filterTypeTitle,FILTERBY_HELP_LINK); filterBy_t *filterBy = NULL; if (cartOptionalString(cart, "ajax") == NULL) @@ -3957,31 +3956,31 @@ puts("
"); char selectStatement[4096]; if (isMultiple) safef(selectStatement, sizeof selectStatement, " (select multiple items - %s)", FILTERBY_HELP_LINK); else selectStatement[0] = 0; if(count == 1) printf("%s by %s%s",filterTypeTitle,filterBy->title,selectStatement); else printf("%s",filterBy->title); printf("
\n"); if (isMultiple && tdbIsBigBed(tdb)) { char cartSettingString[4096]; - safef(cartSettingString, sizeof cartSettingString, "%s.%s", tdb->track, settingString); + safef(cartSettingString, sizeof cartSettingString, "%s.%s", prefix, settingString); printf("Match if "); cgiMakeRadioButton(cartSettingString, FILTERBY_MULTIPLE_LIST_AND, sameString(setting, FILTERBY_MULTIPLE_LIST_AND)); printf(" all "); cgiMakeRadioButton(cartSettingString, FILTERBY_MULTIPLE_LIST_OR, sameString(setting, FILTERBY_MULTIPLE_LIST_OR)); printf(" one or more match "); } // TODO: columnCount (Number of filterBoxes per row) should be configurable through tdb setting // value is always "All", even if label is different, to simplify javascript code int valIx = 0; if (isMultiple) { printf( "\n"); puts("
"); } void filterBySetCfgUi(struct cart *cart, struct trackDb *tdb, - filterBy_t *filterBySet, boolean onOneLine) + filterBy_t *filterBySet, boolean onOneLine, char *prefix) /* Does the filter UI for a list of filterBy structure */ { -filterBySetCfgUiGuts(cart, tdb, filterBySet, onOneLine, "Filter", "fbc", "All"); +filterBySetCfgUiGuts(cart, tdb, filterBySet, onOneLine, "Filter", "fbc", "All", prefix); } void highlightBySetCfgUi(struct cart *cart, struct trackDb *tdb, - filterBy_t *filterBySet, boolean onOneLine) + filterBy_t *filterBySet, boolean onOneLine, char *prefix) /* Does the highlight UI for a list of filterBy structure */ { -filterBySetCfgUiGuts(cart, tdb, filterBySet, onOneLine, "Highlight", "hbc", "None"); +filterBySetCfgUiGuts(cart, tdb, filterBySet, onOneLine, "Highlight", "hbc", "None", prefix); } #define COLOR_BG_DEFAULT_IX 0 #define COLOR_BG_ALTDEFAULT_IX 1 #define DIVIDING_LINE "
\n" #define DIVIDER_PRINT(color) printf(DIVIDING_LINE,COLOR_BG_DEFAULT,(color)) static char *checkBoxIdMakeForTrack(struct trackDb *tdb,members_t** dims,int dimMax, membership_t *membership) // Creates an 'id' string for subtrack checkbox in style that matrix understand: // "cb_dimX_dimY_view_cb" { int len = strlen(tdb->track) + 10; char *id = needMem(len); @@ -4211,31 +4210,31 @@ // composite/view must pass in example subtrack // NOTE: if subtrack types vary then there shouldn't be cfg at composite/view level! while (tdb->subtracks) tdb = tdb->subtracks; switch(cType) { case cfgBedScore: { char *scoreMax = trackDbSettingClosestToHome(tdb, SCORE_FILTER _MAX); int maxScore = (scoreMax ? sqlUnsigned(scoreMax):1000); scoreCfgUi(db, cart,tdb,prefix,title,maxScore,boxed); if(startsWith("bigBed", tdb->type)) - labelCfgUi(db, cart, tdb); + labelCfgUi(db, cart, tdb, prefix); } break; case cfgPeak: encodePeakCfgUi(cart,tdb,prefix,title,boxed); break; case cfgWig: wigCfgUi(cart,tdb,prefix,title,boxed); break; case cfgWigMaf: wigMafCfgUi(cart,tdb,prefix,title,boxed, db); break; case cfgGenePred: genePredCfgUi(db, cart,tdb,prefix,title,boxed); break; case cfgChain: chainCfgUi(db,cart,tdb,prefix,title,boxed, NULL); break; case cfgNetAlign: netAlignCfgUi(db,cart,tdb,prefix,title,boxed); break; @@ -5919,31 +5918,31 @@ boolean isBoxOpened = FALSE; if (numericFiltersShowAll(db, cart, tdb, &isBoxOpened, boxed, parentLevel, name, title) > 0) skipScoreFilter = TRUE; textFiltersShowAll(db, cart, tdb); // Add any multi-selects next filterBy_t *filterBySet = filterBySetGet(tdb,cart,name); if (filterBySet != NULL) { if (!tdbIsComposite(tdb) && cartOptionalString(cart, "ajax") == NULL) jsIncludeFile("hui.js",NULL); if (!isBoxOpened) // Note filterBy boxes are not double "boxed", printf("
"); // if there are no other filters - filterBySetCfgUi(cart,tdb,filterBySet,TRUE); + filterBySetCfgUi(cart,tdb,filterBySet,TRUE, name); filterBySetFree(&filterBySet); skipScoreFilter = TRUE; } // For no good reason scoreFilter is incompatible with filterBy and or numericFilters // FIXME scoreFilter should be implemented inside numericFilters and is currently specificly // excluded to avoid unexpected changes if (skipScoreFilter) { if (isBoxOpened) cfgEndBox(boxed); return; // Cannot have both '*filter' and 'scoreFilter' } @@ -6066,51 +6065,51 @@ for(thisField = fieldList; thisField; thisField = thisField->next) { char *trimLabel = trimSpaces(thisField->name); unsigned colNum = asColumnFindIx(as->columnList, trimLabel); if (colNum == -1) errAbort("cannot find field named '%s' in AS file '%s'", trimLabel, as->name); slAddHead(&list, slPairNew(trimLabel, NULL + colNum)); } slReverse(&list); return list; } -void labelCfgUi(char *db, struct cart *cart, struct trackDb *tdb) +void labelCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *prefix) /* If there is a labelFields for a bigBed, this routine is called to put up the label options. */ { if (trackDbSettingClosestToHomeOn(tdb, "linkIdInName")) return; struct asObject *as = asForDb(tdb, db); if (as == NULL) return; struct slPair *labelList = buildFieldList(tdb, "labelFields", as); struct slPair *defaultLabelList = buildFieldList(tdb, "defaultLabelFields", as); char varName[1024]; if ((labelList == NULL) || sameString(labelList->name, "none")) return; printf("Label: "); struct slPair *thisLabel = labelList; for(; thisLabel; thisLabel = thisLabel->next) { - safef(varName, sizeof(varName), "%s.label.%s", tdb->track, thisLabel->name); + safef(varName, sizeof(varName), "%s.label.%s", prefix, thisLabel->name); boolean isDefault = FALSE; if (defaultLabelList == NULL) isDefault = (thisLabel == labelList); else if (sameString(defaultLabelList->name, "none")) isDefault = FALSE; else isDefault = (slPairFind(defaultLabelList, thisLabel->name) != NULL); boolean option = cartUsualBoolean(cart, varName, isDefault); cgiMakeCheckBox(varName, option); // find comment for the column listed struct asColumn *col = as->columnList; unsigned num = ptToInt(thisLabel->val); for(; col && num--; col = col->next) @@ -6118,31 +6117,31 @@ assert(col); printf(" %s   ", col->comment); } } void pslCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* Put up UI for psl tracks */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); char *typeLine = cloneString(tdb->type); char *words[8]; int wordCount = wordCount = chopLine(typeLine, words); if (sameString(tdb->type, "bigPsl")) - labelCfgUi(db, cart, tdb); + labelCfgUi(db, cart, tdb, name); if (wordCount == 3 && sameWord(words[1], "xeno")) crossSpeciesCfgUi(cart,tdb); baseColorDropLists(cart, tdb, name); indelShowOptionsWithName(cart, tdb, name); cfgEndBox(boxed); } void netAlignCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *prefix, char *title, boolean boxed) /* Put up UI for net tracks */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); boolean parentLevel = isNameAtParentLevel(tdb,prefix); @@ -6515,31 +6514,31 @@ char *value = cartUsualStringClosestToHome(cart, tdb, parentLevel, varSuffix, NULL); boolean checked = (value != NULL) && !sameString(value, "0"); printf("%s%s: ", (i > 0) ? "  " : "", labelsNames[i][0]); cgiMakeCheckBoxMore(varName, checked, NULL); } } void genePredCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* Put up genePred-specific controls */ { char varName[64]; boolean parentLevel = isNameAtParentLevel(tdb,name); char *geneLabel = cartUsualStringClosestToHome(cart, tdb,parentLevel, "label", "gene"); boxed = cfgBeginBoxAndTitle(tdb, boxed, title); -labelCfgUi(db, cart, tdb); +labelCfgUi(db, cart, tdb, name); if (sameString(name, "acembly")) { char *acemblyClass = cartUsualStringClosestToHome(cart,tdb,parentLevel,"type", acemblyEnumToString(0)); printf("

Gene Class: "); acemblyDropDown("acembly.type", acemblyClass); printf(" "); } else if (startsWith("wgEncodeGencode", name)) { // new GENCODEs gencodeLabelControls(db, cart, tdb, name, title, boxed, parentLevel); } else if (sameString("wgEncodeSangerGencode", name) || (startsWith("encodeGencode", name) && !sameString("encodeGencodeRaceFrags", name))) @@ -6565,38 +6564,38 @@ nmdDefault = cartUsualBoolean(cart,varName, FALSE); // TODO: var name (hgt prefix) needs changing before ClosesToHome can be used printf("

Filter out NMD targets."); cgiMakeCheckBox(varName, nmdDefault); } if (!sameString(tdb->track, "tigrGeneIndex") && !sameString(tdb->track, "ensGeneNonCoding") && !sameString(tdb->track, "encodeGencodeRaceFrags")) baseColorDropLists(cart, tdb, name); filterBy_t *filterBySet = filterBySetGet(tdb,cart,name); if (filterBySet != NULL) { printf("
"); - filterBySetCfgUi(cart,tdb,filterBySet,FALSE); + filterBySetCfgUi(cart,tdb,filterBySet,FALSE, name); filterBySetFree(&filterBySet); } filterBy_t *highlightBySet = highlightBySetGet(tdb,cart,name); if (highlightBySet != NULL) { printf("
"); - highlightBySetCfgUi(cart,tdb,highlightBySet,FALSE); + highlightBySetCfgUi(cart,tdb,highlightBySet,FALSE, name); filterBySetFree(&highlightBySet); } wigOption(cart, name, title, tdb); cfgEndBox(boxed); } static boolean isSpeciesOn(struct cart *cart, struct trackDb *tdb, char *species, char *option, int optionSize, boolean defaultState) /* check the cart to see if species is turned off or on (default is defaultState) */ { boolean parentLevel = isNameAtParentLevel(tdb,option); if (*option == '\0') safef(option, optionSize, "%s.%s", tdb->track, species); else {