View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.renderkit.html.scarborough.standard.tag;
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.myfaces.tobago.component.Attributes;
24  import org.apache.myfaces.tobago.component.Facets;
25  import org.apache.myfaces.tobago.component.SelectBooleanCommand;
26  import org.apache.myfaces.tobago.component.SelectOneCommand;
27  import org.apache.myfaces.tobago.component.UIMenuSelectOne;
28  import org.apache.myfaces.tobago.component.UIToolBar;
29  import org.apache.myfaces.tobago.component.UIToolBarSeparator;
30  import org.apache.myfaces.tobago.config.Configurable;
31  import org.apache.myfaces.tobago.context.Markup;
32  import org.apache.myfaces.tobago.context.ResourceManager;
33  import org.apache.myfaces.tobago.context.ResourceManagerUtils;
34  import org.apache.myfaces.tobago.internal.component.AbstractUICommandBase;
35  import org.apache.myfaces.tobago.internal.component.AbstractUIMenu;
36  import org.apache.myfaces.tobago.internal.context.ResourceManagerFactory;
37  import org.apache.myfaces.tobago.layout.Measure;
38  import org.apache.myfaces.tobago.renderkit.LabelWithAccessKey;
39  import org.apache.myfaces.tobago.renderkit.LayoutComponentRendererBase;
40  import org.apache.myfaces.tobago.renderkit.css.Classes;
41  import org.apache.myfaces.tobago.renderkit.css.Style;
42  import org.apache.myfaces.tobago.renderkit.html.DataAttributes;
43  import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
44  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
45  import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
46  import org.apache.myfaces.tobago.renderkit.html.util.CommandRendererHelper;
47  import org.apache.myfaces.tobago.renderkit.html.util.HtmlRendererUtils;
48  import org.apache.myfaces.tobago.renderkit.util.RenderUtils;
49  import org.apache.myfaces.tobago.util.ComponentUtils;
50  import org.apache.myfaces.tobago.util.CreateComponentUtils;
51  import org.apache.myfaces.tobago.util.FacetUtils;
52  import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
53  import org.slf4j.Logger;
54  import org.slf4j.LoggerFactory;
55  
56  import javax.faces.component.UIComponent;
57  import javax.faces.context.FacesContext;
58  import javax.faces.model.SelectItem;
59  import java.io.IOException;
60  import java.util.List;
61  
62  public abstract class ToolBarRendererBase extends LayoutComponentRendererBase {
63  
64    private static final Logger LOG = LoggerFactory.getLogger(ToolBarRendererBase.class);
65  
66    @Override
67    public void prepareRender(FacesContext facesContext, UIComponent component) throws IOException {
68      super.prepareRender(facesContext, component);
69      HtmlRendererUtils.renderDojoDndSource(facesContext, component);
70    }
71  
72    protected String getLabelPosition(UIComponent component) {
73      return (String) component.getAttributes().get(Attributes.LABEL_POSITION);
74    }
75  
76    protected String getIconSize(UIComponent component) {
77      return (String) component.getAttributes().get(Attributes.ICON_SIZE);
78    }
79  
80    protected boolean isRightAligned(UIToolBar toolBar) {
81      return UIToolBar.ORIENTATION_RIGHT.equals(toolBar.getOrientation());
82    }
83  
84    @Override
85    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
86      UIToolBar toolBar = (UIToolBar) component;
87  
88      TobagoResponseWriter writer = HtmlRendererUtils.getTobagoResponseWriter(context);
89  
90      Measure width = Measure.valueOf(-1);
91      for (UIComponent command : toolBar.getChildren()) {
92        if (command instanceof AbstractUICommandBase) {
93          width = renderToolbarCommand(context, toolBar, (AbstractUICommandBase) command, writer, width);
94        } else if (command instanceof UIToolBarSeparator) {
95          width = renderSeparator(context, toolBar, (UIToolBarSeparator) command, writer, width);
96        } else {
97          LOG.error("Illegal UIComponent class in toolbar (not a AbstractUICommandBase):" + command.getClass().getName());
98        }
99      }
100   }
101 
102   private Measure renderToolbarCommand(FacesContext facesContext, UIToolBar toolBar, AbstractUICommandBase command,
103       TobagoResponseWriter writer, Measure width) throws IOException {
104     if (command instanceof SelectBooleanCommand) {
105       return renderSelectBoolean(facesContext, toolBar, command, writer, width);
106     } else if (command instanceof SelectOneCommand) {
107       return renderSelectOne(facesContext, toolBar, command, writer, width);
108     } else {
109       if (command.getFacet(Facets.RADIO) != null) {
110         return renderSelectOne(facesContext, toolBar, command, writer, width);
111       } else if (command.getFacet(Facets.CHECKBOX) != null) {
112         return renderSelectBoolean(facesContext, toolBar, command, writer, width);
113       } else {
114         String onCommandClick = createCommandOnClick(facesContext, command);
115         String onMenuClick = createMenuOnClick(command);
116         return renderToolbarButton(
117             facesContext, toolBar, command, writer, false, onCommandClick, onMenuClick, width);
118       }
119     }
120   }
121 
122   // todo: remove component creation in renderer, for JSF 2.0
123   // todo: One solution is to make <tx:toolBarSelectOne> instead of <tc:toolBarSelectOne>
124   private Measure renderSelectOne(FacesContext facesContext, UIToolBar toolBar, AbstractUICommandBase command,
125       TobagoResponseWriter writer, Measure width) throws IOException {
126 
127     String suffix = createCommandOnClick(facesContext, command);
128     if (suffix == null) {
129       suffix = "";
130     }
131 
132     List<SelectItem> items;
133 
134     UIMenuSelectOne radio = (UIMenuSelectOne) command.getFacet(Facets.RADIO);
135     if (radio == null) {
136       items = RenderUtils.getSelectItems(command);
137       radio = CreateComponentUtils.createUIMenuSelectOneFacet(facesContext, command);
138       radio.setId(facesContext.getViewRoot().createUniqueId());
139     } else {
140       items = RenderUtils.getSelectItems(radio);
141     }
142 
143     if (radio != null) {
144       Object value = radio.getValue();
145 
146       String currentValue = "";
147       boolean markFirst = !ComponentUtils.hasSelectedValue(items, value);
148       String radioId = radio.getClientId(facesContext);
149       for (SelectItem item : items) {
150         final String labelText = item.getLabel();
151         if (labelText != null) {
152           command.getAttributes().put(Attributes.LABEL, labelText);
153         } else {
154           LOG.warn("Menu item has label=null. UICommand.getClientId()=" + command.getClientId(facesContext));
155         }
156 
157         String image = null;
158         if (item instanceof org.apache.myfaces.tobago.model.SelectItem) {
159           image = ((org.apache.myfaces.tobago.model.SelectItem) item).getImage();
160         } else if (LOG.isDebugEnabled()) {
161           LOG.debug("select item is not " + org.apache.myfaces.tobago.model.SelectItem.class.getName());
162         }
163         if (image == null) {
164           image = "image/1x1.gif";
165         }
166         command.getAttributes().put(Attributes.IMAGE, image);
167 
168         if (item.getDescription() != null) {
169           command.getAttributes().put(Attributes.TIP, item.getDescription());
170         }
171 
172         String formattedValue = RenderUtils.getFormattedValue(facesContext, radio, item.getValue());
173         final boolean checked;
174         if (item.getValue().equals(value) || markFirst) {
175           checked = true;
176           markFirst = false;
177           currentValue = formattedValue;
178         } else {
179           checked = false;
180         }
181 
182         String onClick = "Tobago.ToolBar.setRadioValue('" + radioId + "', '" + formattedValue + "');" + suffix;
183         width = renderToolbarButton(facesContext, toolBar, command, writer, checked, onClick, null, width);
184       }
185 
186       writer.startElement(HtmlElements.INPUT, null);
187       writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
188       writer.writeIdAttribute(radioId);
189       writer.writeNameAttribute(radioId);
190       writer.writeAttribute(HtmlAttributes.VALUE, currentValue, true);
191       writer.endElement(HtmlElements.INPUT);
192     }
193     return width;
194   }
195 
196   // todo: remove component creation in renderer, for JSF 2.0
197   // todo: One solution is to make <tx:toolBarCheck> instead of <tc:toolBarCheck>
198   // may be renamed to toolBarSelectBoolean?
199   private Measure renderSelectBoolean(FacesContext facesContext, UIToolBar toolBar, AbstractUICommandBase command,
200       TobagoResponseWriter writer, Measure width) throws IOException {
201 
202     UIComponent checkbox = command.getFacet(Facets.CHECKBOX);
203     if (checkbox == null) {
204       checkbox = CreateComponentUtils.createUISelectBooleanFacetWithId(facesContext, command);
205     }
206 
207     final boolean checked = ComponentUtils.getBooleanAttribute(checkbox, Attributes.VALUE);
208     final String clientId = checkbox.getClientId(facesContext);
209 
210     String onClick = createCommandOnClick(facesContext, command);
211     if (onClick == null) {
212       onClick = "";
213     }
214     onClick = "Tobago.ToolBar.checkToggle('" + clientId + "');" + onClick;
215 
216     width = renderToolbarButton(facesContext, toolBar, command, writer, checked, onClick, null, width);
217 
218     writer.startElement(HtmlElements.INPUT, null);
219     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
220     writer.writeIdAttribute(clientId);
221     writer.writeNameAttribute(clientId);
222     writer.writeAttribute(HtmlAttributes.VALUE, Boolean.toString(checked), false);
223     writer.endElement(HtmlElements.INPUT);
224 
225     return width;
226   }
227 
228 
229   private Measure renderToolbarButton(
230       FacesContext facesContext, UIToolBar toolBar, AbstractUICommandBase command, TobagoResponseWriter writer,
231       boolean selected, String commandClick, String menuClick, Measure width)
232       throws IOException {
233     if (!command.isRendered()) {
234       return width;
235     }
236 
237     //final String clientId = command.getClientId(facesContext);
238     final boolean disabled = ComponentUtils.getBooleanAttribute(command, Attributes.DISABLED);
239     final LabelWithAccessKey label = new LabelWithAccessKey(command);
240     final AbstractUIMenu dropDownMenu = FacetUtils.getDropDownMenu(command);
241     final ResourceManager resources = getResourceManager();
242 
243     final String labelPosition = getLabelPosition(command.getParent());
244     final String iconSize = getIconSize(command.getParent());
245     final String iconName = (String) command.getAttributes().get(Attributes.IMAGE);
246     final boolean lackImage = iconName == null;
247     final String image = lackImage ? null : getImage(facesContext, iconName, iconSize, disabled, selected);
248 
249     final boolean showIcon = !UIToolBar.ICON_OFF.equals(iconSize);
250     final boolean iconBig = UIToolBar.ICON_BIG.equals(iconSize);
251 
252     final boolean showLabelBottom = UIToolBar.LABEL_BOTTOM.equals(labelPosition);
253     final boolean showLabelRight = UIToolBar.LABEL_RIGHT.equals(labelPosition);
254     final boolean showLabel = showLabelBottom || showLabelRight;
255     // two separate buttons for the command and the sub menu
256     final boolean separateButtons = hasAnyCommand(command) && dropDownMenu != null;
257 
258     final Measure paddingTop = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-top");
259     final Measure paddingMiddle = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-middle");
260     final Measure paddingBottom = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-bottom");
261     final Measure paddingLeft = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-left");
262     final Measure paddingCenter = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-center");
263     final Measure paddingRight = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-right");
264     final Measure iconBigHeight = resources.getThemeMeasure(facesContext, toolBar, "custom.icon-big-height");
265     final Measure iconSmallHeight = resources.getThemeMeasure(facesContext, toolBar, "custom.icon-small-height");
266     final Measure iconBigWidth = resources.getThemeMeasure(facesContext, toolBar, "custom.icon-big-width");
267     final Measure iconSmallWidth = resources.getThemeMeasure(facesContext, toolBar, "custom.icon-small-width");
268 
269     // label style
270     final Style labelStyle;
271     if (showLabel) {
272       labelStyle = new Style();
273       labelStyle.setLeft(paddingLeft);
274       labelStyle.setTop(paddingTop);
275       labelStyle.setWidth(RenderUtils.calculateStringWidth(facesContext, toolBar, label.getText()));
276       labelStyle.setHeight(resources.getThemeMeasure(facesContext, toolBar, "custom.label-height"));
277     } else {
278       labelStyle = null;
279     }
280 
281     // button style
282     final Style buttonStyle = new Style();
283     buttonStyle.setLeft(Measure.ZERO);
284     buttonStyle.setTop(Measure.ZERO);
285     buttonStyle.setWidth(paddingLeft.add(paddingRight));
286     buttonStyle.setHeight(paddingBottom.add(paddingTop));
287 
288     // icon style
289     final Style iconStyle;
290 
291     if (showIcon) {
292       iconStyle = new Style();
293       iconStyle.setLeft(paddingLeft);
294       iconStyle.setTop(paddingTop);
295       iconStyle.setHeight(iconBig ? iconBigHeight : iconSmallHeight);
296       if (lackImage && showLabelRight && StringUtils.isNotBlank(label.getText())) {
297         iconStyle.setWidth(Measure.valueOf(1));
298       } else {
299         iconStyle.setWidth(iconBig ? iconBigWidth : iconSmallWidth);
300       }
301       if (showLabelBottom) {
302         labelStyle.setTop(labelStyle.getTop().add(iconStyle.getHeight()).add(paddingMiddle));
303         if (labelStyle.getWidth().lessThan(iconStyle.getWidth())) {
304           // label smaller than icon
305           labelStyle.setLeft(labelStyle.getLeft().add(iconStyle.getWidth().subtract(labelStyle.getWidth()).divide(2)));
306           buttonStyle.setWidth(buttonStyle.getWidth().add(iconStyle.getWidth()));
307         } else {
308           // label bigger than icon
309           iconStyle.setLeft(iconStyle.getLeft().add(labelStyle.getWidth().subtract(iconStyle.getWidth()).divide(2)));
310           buttonStyle.setWidth(buttonStyle.getWidth().add(labelStyle.getWidth()));
311         }
312         buttonStyle.setHeight(
313             buttonStyle.getHeight().add(iconStyle.getHeight()).add(paddingMiddle).add(labelStyle.getHeight()));
314       } else if (showLabelRight) {
315         labelStyle.setTop(labelStyle.getTop().add(iconStyle.getHeight().subtract(labelStyle.getHeight()).divide(2)));
316         labelStyle.setLeft(labelStyle.getLeft().add(iconStyle.getWidth()).add(paddingCenter));
317         buttonStyle.setWidth(
318             buttonStyle.getWidth().add(iconStyle.getWidth()).add(paddingCenter).add(labelStyle.getWidth()));
319         buttonStyle.setHeight(buttonStyle.getHeight().add(iconStyle.getHeight()));
320       } else {
321         buttonStyle.setWidth(buttonStyle.getWidth().add(iconStyle.getWidth()));
322         buttonStyle.setHeight(buttonStyle.getHeight().add(iconStyle.getHeight()));
323       }
324     } else {
325       iconStyle = null;
326       if (showLabel) {
327         // only label
328         buttonStyle.setWidth(buttonStyle.getWidth().add(labelStyle.getWidth()));
329         if (StringUtils.isBlank(label.getText())) {
330           buttonStyle.setWidth(buttonStyle.getWidth().add(iconSmallWidth));
331         }
332         buttonStyle.setHeight(buttonStyle.getHeight().add(labelStyle.getHeight()));
333       } else {
334         // both off: use some reasonable defaults
335         buttonStyle.setWidth(buttonStyle.getWidth().add(iconSmallWidth));
336         buttonStyle.setHeight(buttonStyle.getHeight().add(iconSmallWidth));
337       }
338     }
339 
340     // opener style (for menu popup)
341     final Style openerStyle = new Style();
342     openerStyle.setWidth(resources.getThemeMeasure(facesContext, toolBar, "custom.opener-width"));
343     openerStyle.setHeight(resources.getThemeMeasure(facesContext, toolBar, "custom.opener-height"));
344 
345     final Style menuStyle = new Style();
346     menuStyle.setLeft(buttonStyle.getWidth());
347     menuStyle.setTop(Measure.ZERO);
348     menuStyle.setWidth(paddingLeft.add(openerStyle.getWidth()).add(paddingRight));
349     menuStyle.setHeight(buttonStyle.getHeight());
350 
351     // opener style (for menu popup)
352     openerStyle.setLeft(menuStyle.getWidth().subtract(openerStyle.getWidth()).divide(2));
353     openerStyle.setTop(menuStyle.getHeight().subtract(openerStyle.getHeight()).divide(2));
354 
355     // item style
356     final Style itemStyle = new Style();
357     if (isRightAligned(toolBar)) { // overrides the default in the CSS file.
358       itemStyle.setLeft(resources.getThemeMeasure(facesContext, toolBar, "css.border-right-width"));
359     }
360     itemStyle.setWidth(
361         dropDownMenu != null ? buttonStyle.getWidth().add(menuStyle.getWidth()) : buttonStyle.getWidth());
362     itemStyle.setHeight(buttonStyle.getHeight());
363 
364     // XXX hack
365     if (dropDownMenu != null && lackImage && !showLabel) {
366       itemStyle.setWidth(openerStyle.getWidth());
367       buttonStyle.setWidth(openerStyle.getWidth());
368     }
369 
370     // change values when only have one button
371     if (dropDownMenu != null && !separateButtons && (!lackImage || StringUtils.isNotBlank(label.getText()))) {
372       openerStyle.setLeft(openerStyle.getLeft().add(buttonStyle.getWidth()));
373       buttonStyle.setWidth(buttonStyle.getWidth().add(menuStyle.getWidth()));
374     }
375     
376     // start rendering
377     writer.startElement(HtmlElements.SPAN, command);
378     Markup itemMarkup = Markup.NULL;
379     if (selected) {
380       itemMarkup = itemMarkup.add(Markup.SELECTED);
381     }
382     if (disabled) {
383       itemMarkup = itemMarkup.add(Markup.DISABLED);
384     }
385     writer.writeClassAttribute(Classes.create(toolBar, "item", itemMarkup));
386     HtmlRendererUtils.renderTip(command, writer);
387     writer.writeStyleAttribute(itemStyle);
388 
389     writer.startElement(HtmlElements.SPAN, command);
390     writer.writeClassAttribute(Classes.create(toolBar, "button", selected ? Markup.SELECTED : Markup.NULL));
391     writer.writeStyleAttribute(buttonStyle);
392     if (!toolBar.isTransient()) {
393       writer.writeIdAttribute(command.getClientId(facesContext));
394     }
395     writer.writeAttribute(HtmlAttributes.ONCLICK, commandClick != null ? commandClick : menuClick, true);
396     // render icon
397     if (showIcon && iconName != null) {
398       writer.startElement(HtmlElements.IMG, command);
399       writer.writeAttribute(HtmlAttributes.SRC, image, false);
400       String imageHover
401           = ResourceManagerUtils.getImageWithPath(facesContext, HtmlRendererUtils.createSrc(iconName, "Hover"), true);
402       if (imageHover != null) {
403         writer.writeAttribute(DataAttributes.SRCDEFAULT, image, false);
404         writer.writeAttribute(DataAttributes.SRCHOVER, imageHover, false);
405       }
406       writer.writeAttribute(HtmlAttributes.ALT, label.getText(), true);
407       writer.writeStyleAttribute(iconStyle);
408       writer.endElement(HtmlElements.IMG);
409     }
410     // render label
411     if (showLabel) {
412       writer.startElement(HtmlElements.SPAN, command);
413       writer.writeClassAttribute(Classes.create(toolBar, "label"));
414       writer.writeStyleAttribute(labelStyle);
415       if (label.getText() != null) {
416         HtmlRendererUtils.writeLabelWithAccessKey(writer, label);
417       }
418       writer.endElement(HtmlElements.SPAN);
419     }
420 
421     if (separateButtons) {
422       writer.endElement(HtmlElements.SPAN);
423 
424       writer.startElement(HtmlElements.SPAN, command);
425       writer.writeClassAttribute(Classes.create(toolBar, "menu"));
426       writer.writeStyleAttribute(menuStyle);
427       // todo: span has not type: use data-tobago-type here (TOBAGO-1004)
428       writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.BUTTON, false);
429       writer.writeAttribute(HtmlAttributes.ONCLICK, menuClick, true);
430     }
431 
432     // render sub menu popup button
433     if (dropDownMenu != null) {
434       writer.startElement(HtmlElements.IMG, command);
435       String menuImage = ResourceManagerUtils.getImageWithPath(facesContext, "image/toolbarButtonMenu.gif");
436       writer.writeAttribute(HtmlAttributes.SRC, menuImage, false);
437       writer.writeStyleAttribute(openerStyle);
438       writer.endElement(HtmlElements.IMG);
439       renderDropDownMenu(facesContext, writer, dropDownMenu);
440     }
441     writer.endElement(HtmlElements.SPAN);
442     writer.endElement(HtmlElements.SPAN);
443 
444     return width.add(itemStyle.getWidth()).add(2); // XXX
445     // computation of the width of the toolBar will not be used in the moment.
446   }
447 
448   private Measure renderSeparator(
449       FacesContext facesContext, UIToolBar toolBar, UIToolBarSeparator separator, TobagoResponseWriter writer,
450       Measure width)
451       throws IOException {
452     if (!separator.isRendered()) {
453       return width;
454     }
455 
456     writer.startElement(HtmlElements.SPAN, separator);
457     writer.writeClassAttribute(Classes.create(toolBar, "item", Markup.DISABLED));
458     Style itemStyle = new Style();
459     itemStyle.setHeight(getItemHeight(facesContext, toolBar));
460     itemStyle.setWidth(Measure.valueOf(10));
461     writer.writeStyleAttribute(itemStyle);
462 
463     writer.startElement(HtmlElements.SPAN, separator);
464     writer.writeClassAttribute(Classes.create(toolBar, "separator"));
465     writer.endElement(HtmlElements.SPAN);
466 
467     writer.endElement(HtmlElements.SPAN);
468 
469     return width.add(itemStyle.getWidth()).add(2); // XXX
470     // computation of the width of the toolBar will not be used in the moment.
471   }
472 
473   protected Measure getItemHeight(FacesContext facesContext, Configurable toolBar) {
474     final String iconSize = getIconSize((UIComponent) toolBar);
475     final String labelPosition = getLabelPosition((UIComponent) toolBar);
476 
477     final boolean showIcon = !UIToolBar.ICON_OFF.equals(iconSize);
478     final boolean iconBig = UIToolBar.ICON_BIG.equals(iconSize);
479     final boolean iconSmall = UIToolBar.ICON_SMALL.equals(iconSize);
480     final boolean showLabelBottom = UIToolBar.LABEL_BOTTOM.equals(labelPosition);
481     final boolean showLabelRight = UIToolBar.LABEL_RIGHT.equals(labelPosition);
482     final boolean showLabel = showLabelBottom || showLabelRight;
483 
484     final ResourceManager resources = getResourceManager();
485 
486     final Measure paddingTop = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-top");
487     final Measure paddingMiddle = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-middle");
488     final Measure paddingBottom = resources.getThemeMeasure(facesContext, toolBar, "custom.padding-bottom");
489     final Measure iconHeight = iconBig
490         ? resources.getThemeMeasure(facesContext, toolBar, "custom.icon-big-height")
491         : resources.getThemeMeasure(facesContext, toolBar, "custom.icon-small-height");
492     final Measure labelHeight = resources.getThemeMeasure(facesContext, toolBar, "custom.label-height");
493 
494     Measure result = paddingTop;
495     if (showIcon) {
496       result = result.add(iconHeight);
497       if (showLabel && showLabelBottom) {
498         result = result.add(paddingMiddle);
499         result = result.add(labelHeight);
500       }
501     } else {
502       if (showLabel) {
503         result = result.add(labelHeight);
504       } else {
505         // both off: use some reasonable defaults
506         result = result.add(16);
507       }
508     }
509     result = result.add(paddingBottom);
510     return result;
511   }
512 
513   private String createCommandOnClick(FacesContext facesContext, AbstractUICommandBase command) {
514     if (hasNoCommand(command) && FacetUtils.getDropDownMenu(command) != null) {
515       return null;
516     } else {
517       CommandRendererHelper helper = new CommandRendererHelper(facesContext, command);
518       return helper.getOnclick();
519     }
520   }
521 
522   private boolean hasAnyCommand(AbstractUICommandBase command) {
523     return !hasNoCommand(command);
524   }
525 
526   private boolean hasNoCommand(AbstractUICommandBase command) {
527     return command.getAction() == null
528         && command.getActionListener() == null
529         && command.getActionListeners().length == 0
530         && command.getLink() == null
531         && command.getAttributes().get(Attributes.ONCLICK) == null;
532   }
533 
534   private String createMenuOnClick(AbstractUICommandBase command) {
535     if (FacetUtils.getDropDownMenu(command) != null) {
536       return "jQuery(this).find('a').click(); " 
537           + "if (event.stopPropagation === undefined) { "
538           + "  event.cancelBubble = true; " // IE
539           + "} else { "
540           + "  event.stopPropagation(); " // other
541           + "}"; // todo: register a onclick handler with jQuery
542     } else {
543       return null;
544     }
545   }
546 
547   private String getImage(
548       FacesContext facesContext, String name, String iconSize, boolean disabled, boolean selected) {
549     int pos = name.lastIndexOf('.');
550     if (pos == -1) {
551       pos = name.length(); // avoid exception if no '.' in name
552     }
553     String key = name.substring(0, pos);
554     String ext = name.substring(pos);
555 
556     String size = "";
557     if (UIToolBar.ICON_SMALL.equals(iconSize)) {
558       size = "16";
559     } else if (UIToolBar.ICON_BIG.equals(iconSize)) {
560       size = "32";
561     }
562     String image = null;
563     ResourceManager resourceManager = ResourceManagerFactory.getResourceManager(facesContext);
564     if (disabled && selected) {
565       image = resourceManager.getImage(facesContext, key + "SelectedDisabled" + size + ext, true);
566       if (image == null) {
567         image = resourceManager.getImage(facesContext, key + "SelectedDisabled" + ext, true);
568       }
569     }
570     if (image == null && disabled) {
571       image = resourceManager.getImage(facesContext, key + "Disabled" + size + ext, true);
572       if (image == null) {
573         image = resourceManager.getImage(facesContext, key + "Disabled" + ext, true);
574       }
575     }
576     if (image == null && selected) {
577       image = resourceManager.getImage(facesContext, key + "Selected" + size + ext, true);
578       if (image == null) {
579         image = resourceManager.getImage(facesContext, key + "Selected" + ext, true);
580       }
581     }
582     if (image == null) {
583       image = resourceManager.getImage(facesContext, key + size + ext, true);
584       if (image == null) {
585         image = resourceManager.getImage(facesContext, key + ext, true);
586       }
587     }
588 
589     return facesContext.getExternalContext().getRequestContextPath() + image;
590   }
591 
592   private void renderDropDownMenu(FacesContext facesContext, TobagoResponseWriter writer, AbstractUIMenu dropDownMenu)
593       throws IOException {
594     writer.startElement(HtmlElements.OL, dropDownMenu);
595     // XXX fix naming conventions for CSS classes
596     writer.writeClassAttribute("tobago-menuBar tobago-menu-dropDownMenu");
597     RenderUtils.encode(facesContext, dropDownMenu);
598     writer.endElement(HtmlElements.OL);
599   }
600 
601   @Override
602   public void encodeChildren(FacesContext facesContext, UIComponent component)
603       throws IOException {
604   }
605 
606   @Override
607   public boolean getRendersChildren() {
608     return true;
609   }
610 }