001    package org.apache.myfaces.tobago.renderkit.html;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.apache.commons.collections.set.ListOrderedSet;
021    import org.apache.commons.logging.Log;
022    import org.apache.commons.logging.LogFactory;
023    import org.apache.commons.lang.StringUtils;
024    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_DISABLED;
025    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INLINE;
026    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_READONLY;
027    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE_CLASS;
028    import org.apache.myfaces.tobago.component.ComponentUtil;
029    import org.apache.myfaces.tobago.component.SupportsMarkup;
030    import org.apache.myfaces.tobago.context.ClientProperties;
031    import org.apache.myfaces.tobago.context.Theme;
032    
033    import javax.faces.component.UIComponent;
034    import javax.faces.component.UIInput;
035    import javax.faces.context.FacesContext;
036    import java.io.Serializable;
037    import java.util.Iterator;
038    import java.util.Locale;
039    import java.util.Map;
040    
041    /*
042     * Date: 2007-05-01
043     */
044    
045    public class StyleClasses implements Serializable {
046    
047      private static final long serialVersionUID = 3738052927067803517L;
048    
049      private static final Log LOG = LogFactory.getLog(StyleClasses.class);
050    
051      public static final char SEPERATOR = '-';
052      public static final String PREFIX = "tobago" + SEPERATOR;
053      public static final String MARKUP = SEPERATOR + "markup" + SEPERATOR;
054    
055      private ListOrderedSet classes;
056    
057      public StyleClasses() {
058        classes = new ListOrderedSet();
059      }
060    
061      private StyleClasses(StyleClasses base) {
062        this();
063        classes.addAll(base.classes);
064      }
065    
066      public static StyleClasses ensureStyleClasses(UIComponent component) {
067        Map attributes = component.getAttributes();
068        StyleClasses classes = (StyleClasses) attributes.get(ATTR_STYLE_CLASS);
069        if (classes == null) {
070          classes = new StyleClasses();
071          attributes.put(ATTR_STYLE_CLASS, classes);
072        }
073        return classes;
074      }
075    
076      public static StyleClasses ensureStyleClassesCopy(UIComponent component) {
077        return new StyleClasses(ensureStyleClasses(component));
078      }
079    
080      @Deprecated
081      public void addFullQualifiedClass(String clazz) {
082        classes.add(clazz);
083      }
084    
085      @Deprecated
086      public void removeFullQualifiedClass(String clazz) {
087        classes.remove(clazz);
088      }
089    
090      public void addClass(String renderer, String sub) {
091        classes.add(nameOfClass(renderer, sub));
092      }
093    
094      public void removeClass(String renderer, String sub) {
095        classes.remove(nameOfClass(renderer, sub));
096      }
097    
098      private String nameOfClass(String renderer, String sub) {
099        StringBuilder builder = new StringBuilder();
100        builder.append(PREFIX);
101        builder.append(renderer);
102        builder.append(SEPERATOR);
103        builder.append(sub);
104        return builder.toString();
105      }
106    
107      public void addMarkupClass(String renderer, String markup) {
108        addMarkupClass(renderer, null, markup);
109      }
110    
111      public void removeMarkupClass(String renderer, String markup) {
112        removeMarkupClass(renderer, null, markup);
113      }
114    
115      public void addMarkupClass(String renderer, String sub, String markup) {
116        classes.add(nameOfMarkupClass(renderer, sub, markup));
117      }
118    
119      public void removeMarkupClass(String renderer, String sub, String markup) {
120        classes.remove(nameOfMarkupClass(renderer, sub, markup));
121      }
122    
123      private String nameOfMarkupClass(String renderer, String sub, String markup) {
124        StringBuilder builder = new StringBuilder();
125        builder.append(PREFIX);
126        builder.append(renderer);
127        if (sub != null) {
128          builder.append(SEPERATOR);
129          builder.append(sub);
130        }
131        builder.append(MARKUP);
132        builder.append(markup);
133        return builder.toString();
134      }
135    
136      public void addMarkupClass(UIComponent component, String rendererName) {
137        if (component instanceof SupportsMarkup) {
138          addMarkupClass((SupportsMarkup) component, rendererName, null);
139        }
140      }
141    
142      public void addMarkupClass(SupportsMarkup supportsMarkup, String rendererName, String sub) {
143        for (String markup : supportsMarkup.getMarkup()) {
144          if (!StringUtils.isBlank(markup)) {
145            Theme theme = ClientProperties.getInstance(FacesContext.getCurrentInstance().getViewRoot()).getTheme();
146            if (theme.getRenderersConfig().isMarkupSupported(rendererName, markup)) {
147              addMarkupClass(rendererName, sub, markup);
148            } else if (!"none".equals(markup)) {
149              LOG.warn("Unknown markup='" + markup + "'");
150            }
151          }
152        }
153      }
154    
155      public void addAspectClass(String renderer, Aspect aspect) {
156        classes.add(nameOfAspectClass(renderer, aspect));
157      }
158    
159      public void removeAspectClass(String renderer, Aspect aspect) {
160        classes.remove(nameOfAspectClass(renderer, aspect));
161      }
162    
163      private String nameOfAspectClass(String renderer, Aspect aspect) {
164        StringBuilder builder = new StringBuilder();
165        builder.append(PREFIX);
166        builder.append(renderer);
167        builder.append(aspect);
168        return builder.toString();
169      }
170    
171    
172      public void addAspectClass(String renderer, String sub, Aspect aspect) {
173        classes.add(nameOfAspectClass(renderer, sub, aspect));
174      }
175    
176      public void removeAspectClass(String renderer, String sub, Aspect aspect) {
177        classes.remove(nameOfAspectClass(renderer, sub, aspect));
178      }
179    
180      private String nameOfAspectClass(String renderer, String sub, Aspect aspect) {
181        StringBuilder builder = new StringBuilder();
182        builder.append(PREFIX);
183        builder.append(renderer);
184        builder.append(SEPERATOR);
185        builder.append(sub);
186        builder.append(aspect);
187        return builder.toString();
188      }
189    
190      public void addClasses(StyleClasses styleClasses) {
191        for (String clazz : (Iterable<String>) styleClasses.classes) {
192          classes.add(clazz);
193        }
194      }
195    
196      public void removeClass(String clazz) {
197        classes.remove(clazz);
198      }
199    
200      public void removeTobagoClasses(String rendererName) {
201        for (Iterator i = classes.iterator(); i.hasNext();) {
202          String clazz = (String) i.next();
203          if (clazz.startsWith(PREFIX + rendererName)) {
204            i.remove();
205          }
206        }
207      }
208    
209      public void updateClassAttributeAndMarkup(UIComponent component, String rendererName) {
210        updateClassAttribute(component, rendererName);
211        addMarkupClass(component, rendererName);
212      }
213    
214      public void updateClassAttribute(UIComponent component, String rendererName) {
215        // first remove old tobago-<rendererName>-<type> classes from class-attribute
216        removeTobagoClasses(rendererName);
217    
218        addAspectClass(rendererName, Aspect.DEFAULT);
219        if (ComponentUtil.getBooleanAttribute(component, ATTR_DISABLED)) {
220          addAspectClass(rendererName, Aspect.DISABLED);
221        }
222        if (ComponentUtil.getBooleanAttribute(component, ATTR_READONLY)) {
223          addAspectClass(rendererName, Aspect.READONLY);
224        }
225        if (ComponentUtil.getBooleanAttribute(component, ATTR_INLINE)) {
226          addAspectClass(rendererName, Aspect.INLINE);
227        }
228        if (component instanceof UIInput) {
229          UIInput input = (UIInput) component;
230          if (ComponentUtil.isError(input)) {
231            addAspectClass(rendererName, Aspect.ERROR);
232          }
233          if (input.isRequired()) {
234            addAspectClass(rendererName, Aspect.REQUIRED);
235          }
236        }
237      }
238    
239      @Override
240      public String toString() {
241        StringBuffer buffer = new StringBuffer();
242        for (Iterator i = classes.iterator(); i.hasNext();) {
243          String clazz = (String) i.next();
244          buffer.append(clazz);
245          if (i.hasNext()) {
246            buffer.append(' ');
247          }
248        }
249        return buffer.toString();
250      }
251    
252      public enum Aspect {
253    
254        DEFAULT,
255        DISABLED,
256        READONLY,
257        INLINE,
258        ERROR,
259        REQUIRED;
260    
261        private String aspect;
262    
263        Aspect() {
264          aspect = '-' + name().toLowerCase(Locale.ENGLISH);
265        }
266    
267        @Override
268        public String toString() {
269          return aspect;
270        }
271      }
272    }