e2467a639cc1e98174ffbd9d0da399b3b75bc9ae markd Thu Jul 26 21:33:38 2012 -0700 highlighting by attribute functionality for GENCODE diff --git src/hg/lib/hui.c src/hg/lib/hui.c index 1750298..98ccd2f 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -3318,63 +3318,63 @@ if (first) *first = strtod(a,NULL); freeMem(a); } if (b!=NULL) { if (second) *second = strtod(b,NULL); freeMem(b); } return TRUE; } return FALSE; } -filterBy_t *filterBySetGet(struct trackDb *tdb, struct cart *cart, char *name) +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 { filterBy_t *filterBySet = NULL; -char *setting = trackDbSettingClosestToHome(tdb, FILTER_BY); +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<filterCount;ix++) { char *filter = cloneString(filters[ix]); filterBy_t *filterBy; AllocVar(filterBy); char *first = strchr(filter,':'); if (first != NULL) *first = '\0'; else - errAbort("filterBySetGet() expected ':' divider between table column and label."); + errAbort("filterBySetGet() expected ':' divider between table column and label: %s", filters[ix]); filterBy->column = filter; filter += strlen(filter) + 1; first = strchr(filter,'='); if (first != NULL) *first = '\0'; else - errAbort("filterBySetGet() expected '=' divider between table column and options list."); + errAbort("filterBySetGet() expected '=' divider between table column and options list: %s", filters[ix]); filterBy->title = strSwapChar(filter,'_',' '); // Title does not have underscores filter += strlen(filter) + 1; // Are values indexes to the string titles? if (filter[0] == '+') { filter += 1; filterBy->useIndex = TRUE; } // Now set up each of the values which may have 1-3 parts (value|label{style}) // the slName list will have the 3 parts delimited by null value\0label\0style\0 stripString(filter, "\""); // Remove any double quotes now and chop by commmas filterBy->slValues = slNameListFromComma(filter); struct slName *val = filterBy->slValues; @@ -3417,49 +3417,61 @@ "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."); } } slAddTail(&filterBySet,filterBy); // Keep them in order (only a few) if (cart != NULL) { char suffix[256]; - safef(suffix, sizeof(suffix), "filterBy.%s", filterBy->column); + safef(suffix, sizeof(suffix), "%s.%s", subName, filterBy->column); boolean parentLevel = isNameAtParentLevel(tdb,name); 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(name) + strlen(filterBy->column) + 15; filterBy->htmlName = needMem(len); - safef(filterBy->htmlName, len, "%s.filterBy.%s", name,filterBy->column); + safef(filterBy->htmlName, len, "%s.%s.%s", name,subName,filterBy->column); } freeMem(setting); return filterBySet; } +filterBy_t *filterBySetGet(struct trackDb *tdb, struct cart *cart, char *name) +/* Gets one or more "filterBy" settings (ClosestToHome). returns NULL if not found */ +{ +return filterBySetGetGuts(tdb, cart, name, "filterBy", FILTER_BY); +} + +filterBy_t *highlightBySetGet(struct trackDb *tdb, struct cart *cart, char *name) +/* Gets one or more "highlightBy" settings (ClosestToHome). returns NULL if not found */ +{ +return filterBySetGetGuts(tdb, cart, name, "highlightBy", HIGHLIGHT_BY); +} + void filterBySetFree(filterBy_t **filterBySet) // Free a set of filterBy structs { if (filterBySet != NULL) { while (*filterBySet != NULL) { filterBy_t *filterBy = slPopHead(filterBySet); if (filterBy->slValues != NULL) slNameFreeList(filterBy->slValues); if (filterBy->slChoices != NULL) slNameFreeList(filterBy->slChoices); if (filterBy->htmlName != NULL) freeMem(filterBy->htmlName); freeMem(filterBy->column); @@ -3493,31 +3505,31 @@ } if (dyStringLen(dyClause) == 0) { dyStringFree(&dyClause); return NULL; } if (count > 1) dyStringPrintf(dyClause, ")"); return dyStringCannibalize(&dyClause); } char *filterByClause(filterBy_t *filterBy) // returns the SQL where clause for a single filterBy struct { -if ((filterBy->slChoices == NULL) || (slNameInList(filterBy->slChoices,"All"))) +if (filterByAllChosen(filterBy)) return NULL; else return filterByClauseStd(filterBy); } struct dyString *dyAddFilterByClause(struct cart *cart, struct trackDb *tdb, struct dyString *extraWhere,char *column, boolean *and) // creates the where clause condition to support a filterBy setting. // Format: filterBy column:Title=value,value [column:Title=value|label,value|label,value|label]) // filterBy filters are multiselect's so could have multiple values selected. // thus returns the "column1 in (...) and column2 in (...)" clause. // if 'column' is provided, and there are multiple filterBy columns, only the named column's // clause is returned. // The 'and' param and dyString in/out allows stringing multiple where clauses together { @@ -3560,72 +3572,106 @@ if (notFirst) dyStringPrintf(dyClause, " AND "); dyStringAppend(dyClause, clause); freeMem(clause); notFirst = TRUE; } } if (dyStringLen(dyClause) == 0) { dyStringFree(&dyClause); return NULL; } return dyStringCannibalize(&dyClause); } -void filterBySetCfgUi(struct cart *cart, struct trackDb *tdb, - filterBy_t *filterBySet, boolean onOneLine) -// Does the UI for a list of filterBy structure +void filterBySetCfgUiOption(filterBy_t *filterBy, struct slName *slValue, int ix) +/* output one option for filterBy UI */ +{ +char varName[32]; +char *label = NULL; +char *name = NULL; +if (filterBy->useIndex) + { + safef(varName, sizeof(varName), "%d",ix); + name = varName; + label = slValue->name; + } +else + { + label = (filterBy->valueAndLabel? slValue->name + strlen(slValue->name)+1: slValue->name); + name = slValue->name; + } +printf("<OPTION"); +if (filterBy->slChoices != NULL && slNameInList(filterBy->slChoices,name)) + printf(" SELECTED"); +if (filterBy->useIndex || filterBy->valueAndLabel) + printf(" value='%s'",name); +if (filterBy->styleFollows) + { + char *styler = label + strlen(label)+1; + if (*styler != '\0') + { + if (*styler == '#') // Legacy: just the color that follows + printf(" style='color: %s;'",styler); + else + printf(" style='%s'",styler); + } + } +printf(">%s</OPTION>\n",label); +} + +void filterBySetCfgUiGuts(struct cart *cart, struct trackDb *tdb, + filterBy_t *filterBySet, boolean onOneLine, + char *filterTypeTitle, char *selectIdPrefix, char *allLabel) +// Does the UI for a list of filterBy structure for either filterBy or highlightBy controls { if (filterBySet == NULL) return; #define FILTERBY_HELP_LINK "<A HREF=\"../goldenPath/help/multiView.html\" TARGET=ucscHelp>help</A>" int count = slCount(filterBySet); if (count == 1) puts("<TABLE cellpadding=3><TR valign='top'>"); else printf("<B>Filter items by:</B> (select multiple categories and items - %s)" "<TABLE cellpadding=3><TR valign='top'>\n",FILTERBY_HELP_LINK); filterBy_t *filterBy = NULL; if (cartOptionalString(cart, "ajax") == NULL) { webIncludeResourceFile("ui.dropdownchecklist.css"); jsIncludeFile("ui.dropdownchecklist.js",NULL); jsIncludeFile("ddcl.js",NULL); } int ix=0; -for (filterBy = filterBySet;filterBy != NULL; filterBy = filterBy->next) +for(filterBy = filterBySet;filterBy != NULL; filterBy = filterBy->next, ix++) { puts("<TD>"); if (count == 1) - printf("<B>Filter by %s</B> (select multiple items - %s)", - filterBy->title,FILTERBY_HELP_LINK); + printf("<B>%s by %s</B> (select multiple items - %s)",filterTypeTitle,filterBy->title,FILTERBY_HELP_LINK); else printf("<B>%s</B>",filterBy->title); printf("<BR>\n"); // TODO: columnCount (Number of filterBoxes per row) should be configurable through tdb setting - #define FILTER_BY_FORMAT "<SELECT id='fbc%d' name='%s' multiple style='display: none; " \ - "font-size:.9em;' class='filterBy'><BR>\n" - printf(FILTER_BY_FORMAT,ix,filterBy->htmlName); - ix++; - printf("<OPTION%s>All</OPTION>\n", - (filterBy->slChoices == NULL || slNameInList(filterBy->slChoices,"All") ? " SELECTED" - : "")); + #define FILTER_BY_FORMAT "<SELECT id='%s%d' name='%s' multiple style='display: none; font-size:.9em;' class='filterBy'><BR>\n" + printf(FILTER_BY_FORMAT,selectIdPrefix,ix,filterBy->htmlName); + + // value is always "All", even if label is different, to simplify javascript code + printf("<OPTION%s value=\"All\">%s</OPTION>\n", (filterByAllChosen(filterBy)?" SELECTED":""), allLabel); struct slName *slValue; int ix=1; for (slValue=filterBy->slValues;slValue!=NULL;slValue=slValue->next,ix++) { char varName[32]; char *label = NULL; char *name = NULL; if (filterBy->useIndex) { safef(varName, sizeof(varName), "%d",ix); name = varName; label = slValue->name; } else @@ -3644,32 +3690,44 @@ char *styler = label + strlen(label)+1; if (*styler != '\0') { if (*styler == '#') // Legacy: just the color that follows printf(" style='color: %s;'",styler); else printf(" style='%s'",styler); } } printf(">%s</OPTION>\n",label); } } printf("</SELECT>\n"); puts("</TR></TABLE>"); +} -return; +void filterBySetCfgUi(struct cart *cart, struct trackDb *tdb, + filterBy_t *filterBySet, boolean onOneLine) +/* Does the filter UI for a list of filterBy structure */ +{ +filterBySetCfgUiGuts(cart, tdb, filterBySet, onOneLine, "Filter", "fbc", "All"); +} + +void highlightBySetCfgUi(struct cart *cart, struct trackDb *tdb, + filterBy_t *filterBySet, boolean onOneLine) +/* Does the highlight UI for a list of filterBy structure */ +{ +filterBySetCfgUiGuts(cart, tdb, filterBySet, onOneLine, "Highlight", "hbc", "None"); } #define COLOR_BG_DEFAULT_IX 0 #define COLOR_BG_ALTDEFAULT_IX 1 #define DIVIDING_LINE "<TR valign=\"CENTER\" line-height=\"1\" BGCOLOR=\"%s\"><TH colspan=\"5\" " \ "align=\"CENTER\"><hr noshade color=\"%s\" width=\"100%%\"></TD></TR>\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); @@ -5710,30 +5768,37 @@ 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("<BR>"); filterBySetCfgUi(cart,tdb,filterBySet,FALSE); filterBySetFree(&filterBySet); } +filterBy_t *highlightBySet = highlightBySetGet(tdb,cart,name); +if (highlightBySet != NULL) + { + printf("<BR>"); + highlightBySetCfgUi(cart,tdb,highlightBySet,FALSE); + filterBySetFree(&highlightBySet); + } 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 { char *suffix = option + strlen(option); int suffixSize = optionSize - strlen(option); safef(suffix,suffixSize,".%s",species);