/******************************************************************************* * Copyright (c) 2007-2008 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributor: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.jsf.vpe.richfaces.template; import java.text.MessageFormat; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import org.jboss.tools.jsf.vpe.richfaces.ComponentUtil; import org.jboss.tools.vpe.editor.VpeVisualDomBuilder; import org.jboss.tools.vpe.editor.context.VpePageContext; import org.jboss.tools.vpe.editor.template.VpeCreationData; import org.jboss.tools.vpe.editor.util.Constants; import org.jboss.tools.vpe.editor.util.HTML; import org.jboss.tools.vpe.editor.util.VpeStyleUtil; import org.mozilla.interfaces.nsIDOMDocument; import org.mozilla.interfaces.nsIDOMElement; import org.mozilla.interfaces.nsIDOMNode; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * @author Eugene Stherbin * @author yradtsevich */ public class RichFacesComboBoxTemplateHelper { private static final WeakHashMap<Node, Object> expandedComboBoxes = new WeakHashMap<Node, Object>(); private static final String DISABLED_ATTR_NAME = "disabled"; //$NON-NLS-1$ private static final String BUTTON_ICON_CLASSES_DISABLED = "rich-combobox-font-inactive rich-combobox-button-icon-disabled rich-combobox-button-inactive"; //$NON-NLS-1$ private static final String BUTTON_ICON_CLASSES = "rich-combobox-font-inactive rich-combobox-button-icon-inactive rich-combobox-button-inactive"; //$NON-NLS-1$ private static final String SECOND_DIV = "secondDiv"; //$NON-NLS-1$ private static final String THIRD_DIV = "thirdDiv"; //$NON-NLS-1$ private static final String THIRD_EMPTY_DIV = "thirdEmptyDiv"; //$NON-NLS-1$ private static final String TEXT_FIELD = "textField"; //$NON-NLS-1$ private static final String BUTTON_ICON = "buttonIcon"; //$NON-NLS-1$ /** CSS_FILE_NAME. */ private static final String CSS_FILE_NAME = "comboBox/comboBox.css"; //$NON-NLS-1$ /** The Constant DEFAULT_LIST_WIDTH. */ private static final String DEFAULT_LIST_WIDTH = "150px"; //$NON-NLS-1$ /** IMAGE_NAME_DOWN. */ private static final String IMAGE_NAME_DOWN = "/comboBox/down.gif"; //$NON-NLS-1$ /** The Constant BUTTON_BACKGROUND. */ private static final String BUTTON_BACKGROUND = "buttonBackground"; //$NON-NLS-1$ /** The Constant STYLE_EXT. */ private static final String STYLE_EXT = "richFacesComboBox"; //$NON-NLS-1$ private static final int LIST_ITEM_HEIGHT_DEFAULT_VALUE = 18; /** The style clasess. */ private final Map<String, String> styleClasess = new HashMap<String, String>(); /** The source align. */ // Commented because of not working alignment in RichFaces implementation // private String sourceAlign; /** The source button style. */ private String sourceButtonStyle; /** The source default label. */ private String sourceDefaultLabel = null; /** The source list height. */ private String sourceListHeight; /** The source list width. */ private String sourceListWidth; /** The source value. */ private String sourceValue; /** The source width. */ private String sourceWidth; /** The source style. */ private String sourceStyle; /** The source input style. */ private String sourceInputStyle; /** The source input class. */ private String sourceInputClass; /** The source list style. */ private String sourceListStyle; /** The source list class. */ private String sourceListClass; /** The source item class. */ private String sourceItemClass; /** Source button icon **/ private String sourceButtonIcon; private String sourceButtonIconInactive; private String sourceButtonIconDisabled; private boolean disabled; private boolean expanded; private final VpePageContext pageContext; private final Node sourceNode; private final nsIDOMDocument visualDocument; private final VpeCreationData vpeCreationData; /** * The Constructor. */ public RichFacesComboBoxTemplateHelper(final VpePageContext pageContext, final Node sourceNode, final nsIDOMDocument visualDocument) { this.pageContext = pageContext; this.sourceNode = sourceNode; this.visualDocument = visualDocument; initDefaultClasses(); vpeCreationData = create(); } /** * Calculate with for div. * * @param with the with * @param minus the minus * * @return the string */ private static String calculateWithForDiv(final String with, final int minus) { try { Integer intValue = 0; if (with.endsWith("px")) { //$NON-NLS-1$ intValue = Integer.parseInt(with.substring(0, with.length() - 2)); } else { intValue = Integer.parseInt(with); } return String.valueOf((intValue - minus)) + "px"; //$NON-NLS-1$ } catch (final NumberFormatException e) { return with; } } public VpeCreationData getVpeCreationData() { return vpeCreationData; } /** * Create. * * @param visualDocument the visual document * @param sourceNode the source node * @param pageContext the page context * * @return the vpe creation data */ private VpeCreationData create() { ComponentUtil.setCSSLink(pageContext, CSS_FILE_NAME, STYLE_EXT); final Element source = (Element) sourceNode; prepareData(source); final nsIDOMElement rootDiv = visualDocument.createElement(HTML.TAG_DIV); //Fix https://jira.jboss.org/jira/browse/JBIDE-2430 issue with resizement. rootDiv.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_WIDTH + Constants.COLON+sourceWidth); final nsIDOMElement comboBoxDiv = visualDocument.createElement(HTML.TAG_DIV); final nsIDOMElement secondDiv = visualDocument.createElement(HTML.TAG_DIV); // Commented because of not working alignment in RichFaces implementation // comboBoxDiv.setAttribute(HTML.ATTR_ALIGN, this.sourceAlign); // secondDiv.setAttribute(HTML.ATTR_ALIGN, this.sourceAlign); //comboBoxDiv.setAttribute(HTML.ATTR_CLASS, styleClasess.get("secondDiv")); //$NON-NLS-1$ secondDiv.setAttribute(HTML.ATTR_CLASS, styleClasess.get(SECOND_DIV)); String secondDivSubStyle = "; position: {0}; z-index: {1} ;"; //$NON-NLS-1$ if (expanded) { secondDivSubStyle = MessageFormat.format(secondDivSubStyle, "relative", "2"); //$NON-NLS-1$ //$NON-NLS-2$ } else { secondDivSubStyle = MessageFormat.format(secondDivSubStyle, "static", "0"); //$NON-NLS-1$ //$NON-NLS-2$ } comboBoxDiv.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_WIDTH + Constants.COLON + sourceListWidth + Constants.SEMICOLON + secondDivSubStyle); secondDiv.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_WIDTH + Constants.COLON + sourceListWidth + Constants.SEMICOLON + secondDivSubStyle + sourceStyle); final nsIDOMElement thirdDiv = visualDocument.createElement(HTML.TAG_DIV); thirdDiv.setAttribute(HTML.ATTR_CLASS, styleClasess.get(THIRD_DIV)); thirdDiv.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_WIDTH + Constants.COLON + sourceWidth + "; z-index: 1;"); //$NON-NLS-1$ final nsIDOMElement textField = visualDocument.createElement(HTML.TAG_INPUT); textField.setAttribute(HTML.ATTR_TYPE, HTML.VALUE_TYPE_TEXT); textField.setAttribute(HTML.ATTR_CLASS, (styleClasess.get(TEXT_FIELD) + Constants.WHITE_SPACE + sourceInputClass).trim()); textField.setAttribute("autocomplete", "off"); //$NON-NLS-1$ //$NON-NLS-2$ textField.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_WIDTH + Constants.COLON + calculateWithForDiv(sourceWidth, 17) + Constants.SEMICOLON + sourceInputStyle); String value = null; if (ComponentUtil.isNotBlank(sourceDefaultLabel)) { value = sourceDefaultLabel; } else if (ComponentUtil.isNotBlank(sourceValue) && ComponentUtil.isBlank(sourceDefaultLabel)) { value = sourceValue; } if (value != null) { textField.setAttribute(RichFaces.ATTR_VALUE, value); } final nsIDOMElement buttonBackground = visualDocument.createElement(HTML.TAG_INPUT); buttonBackground.setAttribute(HTML.ATTR_TYPE, HTML.VALUE_TYPE_TEXT); if (disabled) { styleClasess.put(BUTTON_ICON, BUTTON_ICON_CLASSES_DISABLED); } else { styleClasess.put(BUTTON_ICON, BUTTON_ICON_CLASSES); } buttonBackground.setAttribute(HTML.ATTR_CLASS, styleClasess.get(BUTTON_BACKGROUND)); buttonBackground.setAttribute(HTML.ATTR_READONLY, Constants.TRUE); buttonBackground.setAttribute(VpeVisualDomBuilder.VPE_USER_TOGGLE_ID, String.valueOf(0)); if (sourceButtonStyle != null) { buttonBackground.setAttribute(HTML.ATTR_STYLE, sourceButtonStyle); } final nsIDOMElement buttonIcon = visualDocument.createElement(HTML.TAG_INPUT); buttonIcon.setAttribute(HTML.ATTR_TYPE, HTML.VALUE_TYPE_TEXT); ; buttonIcon.setAttribute(HTML.ATTR_CLASS, styleClasess.get(BUTTON_ICON)); buttonIcon.setAttribute(HTML.ATTR_READONLY, Constants.TRUE); buttonIcon.setAttribute(VpeVisualDomBuilder.VPE_USER_TOGGLE_ID, String.valueOf(0)); if (sourceButtonStyle != null) { buttonIcon.setAttribute(HTML.ATTR_STYLE, sourceButtonStyle); } String actualSourceButton; if (disabled) { actualSourceButton = sourceButtonIconDisabled; } else if (expanded) { actualSourceButton = sourceButtonIcon; } else { actualSourceButton = sourceButtonIconInactive; } if (ComponentUtil.isNotBlank(actualSourceButton) && (actualSourceButton != IMAGE_NAME_DOWN)) { String buttonIconPath = VpeStyleUtil.addFullPathToImgSrc(actualSourceButton, pageContext, true); buttonIconPath = buttonIconPath.replace('\\', '/'); final String style = "background-image: url(" + buttonIconPath + ")"; //$NON-NLS-1$ //$NON-NLS-2$ buttonIcon.setAttribute(HTML.ATTR_STYLE, buttonIcon.getAttribute(HTML.ATTR_STYLE) + style); } final nsIDOMElement forthEmptyDiv = visualDocument.createElement(HTML.TAG_DIV); forthEmptyDiv.setAttribute(HTML.ATTR_CLASS, styleClasess.get("forthEmptyDiv")); //$NON-NLS-1$ forthEmptyDiv.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_WIDTH + Constants.COLON + calculateWithForDiv(sourceWidth, 10)); forthEmptyDiv.appendChild(visualDocument.createTextNode("Struts")); //$NON-NLS-1$ rootDiv.appendChild(comboBoxDiv); comboBoxDiv.appendChild(secondDiv); secondDiv.appendChild(thirdDiv); if (expanded) { comboBoxDiv.appendChild(createToogleDiv()); } thirdDiv.appendChild(textField); thirdDiv.appendChild(buttonBackground); thirdDiv.appendChild(buttonIcon); thirdDiv.appendChild(forthEmptyDiv); final VpeCreationData creationData = new VpeCreationData(rootDiv); return creationData; } /** * Creates the toogle div. * * @param visualDocument the visual document * @param pageContext the page context * @param source the source * * @return the ns IDOM node */ private nsIDOMNode createToogleDiv() { final nsIDOMElement thirdEmptyDiv = visualDocument.createElement(HTML.TAG_DIV); thirdEmptyDiv.setAttribute(HTML.ATTR_STYLE, sourceListStyle + Constants.SEMICOLON + " z-index: 3; position: absolute; visibility: visible; top: 16px; left: 0px;"); //$NON-NLS-1$ thirdEmptyDiv.setAttribute(HTML.ATTR_CLASS, styleClasess.get(THIRD_EMPTY_DIV) + " " + sourceListClass); //$NON-NLS-1$ thirdEmptyDiv.setAttribute(HTML.ATTR_STYLE, "z-index: 3; position: absolute; visibility: visible; top: 16px; left: 0px;"); //$NON-NLS-1$ final nsIDOMElement shadovDiv = visualDocument.createElement(HTML.TAG_DIV); final nsIDOMElement positionDiv = visualDocument.createElement(HTML.TAG_DIV); positionDiv.setAttribute(HTML.ATTR_CLASS, "rich-combobox-list-position"); //$NON-NLS-1$ final nsIDOMElement decorationDiv = visualDocument.createElement(HTML.TAG_DIV); decorationDiv.setAttribute(HTML.ATTR_CLASS, "rich-combobox-list-decoration"); //$NON-NLS-1$ // decorationDiv.setAttribute(HTML.ATTR_STYLE, // "height: 54px; width: 208px;"); final nsIDOMElement scrollDiv = visualDocument.createElement(HTML.TAG_DIV); scrollDiv.setAttribute(HTML.ATTR_CLASS, "rich-combobox-list-scroll"); //$NON-NLS-1$ final List<Element> items = ComponentUtil.getSelectItems(sourceNode.getChildNodes()); int defaultHeight = LIST_ITEM_HEIGHT_DEFAULT_VALUE; if((items!=null) && (items.size() > 1)){ defaultHeight = ((items.size() - 1)* LIST_ITEM_HEIGHT_DEFAULT_VALUE); } final String listHeight = ComponentUtil.isNotBlank(sourceListHeight) ? sourceListHeight : String.valueOf(defaultHeight) + "px"; //$NON-NLS-1$ scrollDiv.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_MAX_HEIGHT + Constants.COLON + listHeight + Constants.SEMICOLON + HTML.STYLE_PARAMETER_WIDTH + Constants.COLON + calculateWithForDiv(sourceListWidth, 2)); final List<Element> selectItems = ComponentUtil.getSelectItems(sourceNode.getChildNodes()); if (selectItems.size() > 0) { for (final Element e : selectItems) { scrollDiv.appendChild(createSelectItem(e)); } } shadovDiv.setAttribute(HTML.ATTR_CLASS, "rich-combobox-shadow"); //$NON-NLS-1$ final nsIDOMElement table = visualDocument.createElement(HTML.TAG_TABLE); table.setAttribute(HTML.ATTR_CELLPADDING, "0"); //$NON-NLS-1$ table.setAttribute(HTML.ATTR_CELLSPACING, "0"); //$NON-NLS-1$ table.setAttribute(HTML.ATTR_BORDER, "0"); //$NON-NLS-1$ String width = Constants.EMPTY; try { int w = ComponentUtil.parseWidthHeightValue(sourceListWidth); w += 7; width = String.valueOf(w); } catch (final NumberFormatException e) { width = "217"; //$NON-NLS-1$ } table.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_WIDTH + Constants.COLON + width + Constants.PIXEL + Constants.SEMICOLON + HTML.STYLE_PARAMETER_HEIGHT + Constants.COLON + "63px;"); //$NON-NLS-1$ final nsIDOMElement tr1 = visualDocument.createElement(HTML.TAG_TR); final nsIDOMElement tr2 = visualDocument.createElement(HTML.TAG_TR); final nsIDOMElement tr1_td1 = visualDocument.createElement(HTML.TAG_TD); final nsIDOMElement tr1_td2 = visualDocument.createElement(HTML.TAG_TD); final nsIDOMElement tr2_td1 = visualDocument.createElement(HTML.TAG_TD); final nsIDOMElement tr2_td2 = visualDocument.createElement(HTML.TAG_TD); final nsIDOMElement tr1_td1_img = visualDocument.createElement(HTML.TAG_IMG); final nsIDOMElement tr1_td2_img = visualDocument.createElement(HTML.TAG_IMG); final nsIDOMElement tr2_td1_img = visualDocument.createElement(HTML.TAG_IMG); final nsIDOMElement tr2_td2_img = visualDocument.createElement(HTML.TAG_IMG); tr1_td1.setAttribute(HTML.ATTR_CLASS, "rich-combobox-shadow-tl"); //$NON-NLS-1$ tr1_td2.setAttribute(HTML.ATTR_CLASS, "rich-combobox-shadow-tr"); //$NON-NLS-1$ tr2_td1.setAttribute(HTML.ATTR_CLASS, "rich-combobox-shadow-bl"); //$NON-NLS-1$ tr2_td2.setAttribute(HTML.ATTR_CLASS, "rich-combobox-shadow-br"); //$NON-NLS-1$ setUpImg(tr1_td1_img, 10, 1, 0, "comboBox/spacer.gif"); //$NON-NLS-1$ setUpImg(tr1_td2_img, 1, 10, 0, "comboBox/spacer.gif"); //$NON-NLS-1$ setUpImg(tr2_td1_img, 1, 10, 0, "comboBox/spacer.gif"); //$NON-NLS-1$ setUpImg(tr2_td2_img, 10, 1, 0, "comboBox/spacer.gif"); //$NON-NLS-1$ thirdEmptyDiv.appendChild(shadovDiv); shadovDiv.appendChild(table); thirdEmptyDiv.appendChild(positionDiv); positionDiv.appendChild(decorationDiv); decorationDiv.appendChild(scrollDiv); table.appendChild(tr1); table.appendChild(tr2); tr1.appendChild(tr1_td1); tr1.appendChild(tr1_td2); tr2.appendChild(tr2_td1); tr2.appendChild(tr2_td2); tr1_td1.appendChild(tr1_td1_img); tr1_td1.appendChild(visualDocument.createElement(HTML.TAG_BR)); tr1_td2.appendChild(tr1_td2_img); tr1_td2.appendChild(visualDocument.createElement(HTML.TAG_BR)); tr2_td1.appendChild(tr2_td1_img); tr2_td1.appendChild(visualDocument.createElement(HTML.TAG_BR)); tr2_td2.appendChild(tr2_td2_img); tr2_td2.appendChild(visualDocument.createElement(HTML.TAG_BR)); return thirdEmptyDiv; } /** * Creates the select item. * * @param visualDocument the visual document * @param e the e * * @return the ns IDOM node */ private nsIDOMNode createSelectItem(final Element e) { final nsIDOMElement item = visualDocument.createElement(HTML.TAG_SPAN); item.setAttribute(HTML.ATTR_CLASS, "rich-combobox-item " + sourceItemClass); //$NON-NLS-1$ item.appendChild(visualDocument.createTextNode(ComponentUtil.getSelectItemValue(e))); return item; } /** * Inits the default classes. */ private void initDefaultClasses() { styleClasess.put(SECOND_DIV, "rich-combobox-font rich-combobox"); //$NON-NLS-1$ styleClasess.put(THIRD_DIV, "rich-combobox-font rich-combobox-shell"); //$NON-NLS-1$ styleClasess.put(THIRD_EMPTY_DIV, "rich-combobox-list-cord"); //$NON-NLS-1$ styleClasess.put(TEXT_FIELD, "rich-combobox-font-disabled rich-combobox-input-inactive"); //$NON-NLS-1$ styleClasess.put(BUTTON_BACKGROUND, "rich-combobox-font-inactive rich-combobox-button-background rich-combobox-button-inactive"); //$NON-NLS-1$ styleClasess.put(BUTTON_ICON, BUTTON_ICON_CLASSES); styleClasess.put("forthEmptyDiv", "rich-combobox-strut rich-combobox-font"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Prepare data. * * @param source the source */ private void prepareData(final Element source) { final AttributeMap attributeMap = new AttributeMap(source); // Commented because of not working alignment in RichFaces implementation // if (attributeMap.isBlank(RichFaces.ATTR_ALIGN)) { // this.sourceAlign = DEFAULT_ALIGN; // } else { // this.sourceAlign = attributeMap.getString(RichFaces.ATTR_ALIGN); // } if (attributeMap.isBlank(RichFaces.ATTR_LIST_WIDTH)) { sourceListWidth = DEFAULT_LIST_WIDTH; } else { sourceListWidth = attributeMap.getString(RichFaces.ATTR_LIST_WIDTH); } sourceListHeight = attributeMap.getString(RichFaces.ATTR_LIST_HEIGHT); if (attributeMap.isBlank(RichFaces.ATTR_WIDTH)) { sourceWidth = DEFAULT_LIST_WIDTH; } else { sourceWidth = attributeMap.getString(RichFaces.ATTR_WIDTH); if(sourceListWidth == DEFAULT_LIST_WIDTH) { sourceListWidth = sourceWidth; } } if (ComponentUtil.isNotBlank(sourceWidth) && (sourceWidth != DEFAULT_LIST_WIDTH)) { if(!sourceWidth.endsWith(Constants.PIXEL)){ try { final int intValue = Integer.parseInt(sourceWidth); sourceWidth = String.valueOf(intValue)+Constants.PIXEL; } catch (final NumberFormatException e) { sourceWidth = DEFAULT_LIST_WIDTH; sourceListWidth = DEFAULT_LIST_WIDTH; } } } sourceDefaultLabel = attributeMap.getString("defaultLabel"); //$NON-NLS-1$ sourceValue = attributeMap.getString( RichFaces.ATTR_VALUE); sourceButtonStyle = attributeMap.getString("buttonStyle"); //$NON-NLS-1$ final String sourceStyleClasess = attributeMap.getString(RichFaces.ATTR_STYLE_CLASS); if (ComponentUtil.isNotBlank(sourceStyleClasess)) { styleClasess.put(SECOND_DIV, styleClasess.get(SECOND_DIV) + " " + sourceStyleClasess); //$NON-NLS-1$ } sourceStyle = attributeMap.getString(HTML.ATTR_STYLE); sourceInputStyle = attributeMap.getString("inputStyle"); //$NON-NLS-1$ sourceInputClass = attributeMap.getString("inputClass"); //$NON-NLS-1$ sourceListClass = attributeMap.getString("listClass"); //$NON-NLS-1$ sourceListStyle = attributeMap.getString("listStyle"); //$NON-NLS-1$ sourceItemClass = attributeMap.getString("itemClass"); //$NON-NLS-1$ sourceButtonIcon = attributeMap.getString(BUTTON_ICON); sourceButtonIconInactive = attributeMap.getString("buttonIconInactive"); //$NON-NLS-1$ sourceButtonIconDisabled = attributeMap.getString("buttonIconDisabled"); //$NON-NLS-1$ disabled = isDisabled(attributeMap); expanded = isExpanded(source); if(ComponentUtil.isBlank(sourceButtonIcon)){ sourceButtonIcon = IMAGE_NAME_DOWN; } } /** * Sets the up img. * * @param i * * @param width the width * @param height the height * @param img the img * @param j * * @param image the image * @param border the border * @param td1Img */ protected static void setUpImg(final nsIDOMElement img, final int width, final int height, final int border, final String image) { ComponentUtil.setImg(img, image); img.setAttribute(HTML.ATTR_WIDTH, String.valueOf(width)); img.setAttribute(HTML.ATTR_HEIGHT, String.valueOf(height)); img.setAttribute(HTML.ATTR_BORDER, String.valueOf(border)); } /** * Inverts <code>expanded</code> state of the ComboBox * * @param builder the builder * @param sourceNode the source node * @param toggleId the toggle id */ public static void toggle(final VpeVisualDomBuilder builder, final Node sourceNode, final String toggleId) { AttributeMap attributes = new AttributeMap((Element)sourceNode); if (isDisabled(attributes) || isExpanded(sourceNode)) { expandedComboBoxes.remove(sourceNode); } else { expandedComboBoxes.put(sourceNode, null); } } public static void stopToggling(final Node sourceNode) { expandedComboBoxes.remove(sourceNode); } public static boolean isDisabled(final AttributeMap attributes) { return attributes.getBoolean(DISABLED_ATTR_NAME) == Boolean.TRUE; } private static boolean isExpanded(Node node) { return expandedComboBoxes.containsKey(node); } }