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 static org.apache.myfaces.tobago.TobagoConstants.ATTR_DISABLED;
024    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INLINE;
025    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_READONLY;
026    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE_CLASS;
027    import org.apache.myfaces.tobago.component.ComponentUtil;
028    import org.apache.myfaces.tobago.component.SupportsMarkup;
029    import org.apache.myfaces.tobago.context.Theme;
030    import org.apache.myfaces.tobago.context.ClientProperties;
031    
032    import javax.faces.component.UIComponent;
033    import javax.faces.component.UIInput;
034    import javax.faces.context.FacesContext;
035    import java.io.Serializable;
036    import java.util.Iterator;
037    import java.util.Map;
038    
039    /*
040     * Date: 2007-05-01
041     */
042    
043    public class StyleClasses implements Serializable {
044    
045      private static final Log LOG = LogFactory.getLog(StyleClasses.class);
046    
047      public static final char SEPERATOR = '-';
048      public static final String PREFIX = "tobago" + SEPERATOR;
049      public static final String MARKUP = SEPERATOR + "markup" + SEPERATOR;
050    
051      private ListOrderedSet classes;
052    
053      public StyleClasses() {
054        classes = new ListOrderedSet();
055      }
056    
057      private StyleClasses(StyleClasses base) {
058        this();
059        classes.addAll(base.classes);
060      }
061    
062      public static StyleClasses ensureStyleClasses(UIComponent component) {
063        Map attributes = component.getAttributes();
064        StyleClasses classes = (StyleClasses) attributes.get(ATTR_STYLE_CLASS);
065        if (classes == null) {
066          classes = new StyleClasses();
067          attributes.put(ATTR_STYLE_CLASS, classes);
068        }
069        return classes;
070      }
071    
072      public static StyleClasses ensureStyleClassesCopy(UIComponent component) {
073        return new StyleClasses(ensureStyleClasses(component));
074      }
075    
076      @Deprecated
077      public void addFullQualifiedClass(String clazz) {
078        classes.add(clazz);
079      }
080    
081      public void addClass(String renderer, String sub) {
082        StringBuilder builder = new StringBuilder();
083        builder.append(PREFIX);
084        builder.append(renderer);
085        builder.append(SEPERATOR);
086        builder.append(sub);
087        classes.add(builder.toString());
088      }
089    
090      public void addMarkupClass(String renderer, String markup) {
091        StringBuilder builder = new StringBuilder();
092        builder.append(PREFIX);
093        builder.append(renderer);
094        builder.append(MARKUP);
095        builder.append(markup);
096        classes.add(builder.toString());
097      }
098    
099      public void addMarkupClass(String renderer, String sub, String markup) {
100        StringBuilder builder = new StringBuilder();
101        builder.append(PREFIX);
102        builder.append(renderer);
103        builder.append(SEPERATOR);
104        builder.append(sub);
105        builder.append(MARKUP);
106        builder.append(markup);
107        classes.add(builder.toString());
108      }
109    
110      public void addMarkupClass(UIComponent component, String rendererName) {
111        if (component instanceof SupportsMarkup) {
112          String[] markups = ((SupportsMarkup) component).getMarkup();
113          for (String markup: markups) {
114            Theme theme = ClientProperties.getInstance(FacesContext.getCurrentInstance().getViewRoot()).getTheme();
115            if (theme.getRenderersConfig().isMarkupSupported(rendererName, markup)) {
116              addMarkupClass(rendererName, markup);
117            } else {
118              LOG.warn("Unknown markup='" + markup + "'");
119            }
120          }
121        }
122      }
123    
124      public void addMarkupClass(UIComponent component, String rendererName, String sub) {
125        if (component instanceof SupportsMarkup) {
126          String[] markups = ((SupportsMarkup) component).getMarkup();
127          for (String markup: markups) {
128            Theme theme = ClientProperties.getInstance(FacesContext.getCurrentInstance().getViewRoot()).getTheme();
129            if (theme.getRenderersConfig().isMarkupSupported(rendererName, markup)) {
130              addMarkupClass(rendererName, sub, markup);
131            } else {
132              LOG.warn("Unknown markup='" + markup + "'");
133            }
134          }
135        }
136      }
137    
138      public void addAspectClass(String renderer, Aspect aspect) {
139        StringBuilder builder = new StringBuilder();
140        builder.append(PREFIX);
141        builder.append(renderer);
142        builder.append(aspect);
143        classes.add(builder.toString());
144      }
145    
146      public void removeAspectClass(String renderer, Aspect aspect) {
147        StringBuilder builder = new StringBuilder();
148        builder.append(PREFIX);
149        builder.append(renderer);
150        builder.append(aspect);
151        classes.remove(builder.toString());
152      }
153    
154      public void addAspectClass(String renderer, String sub, Aspect aspect) {
155        StringBuilder builder = new StringBuilder();
156        builder.append(PREFIX);
157        builder.append(renderer);
158        builder.append(SEPERATOR);
159        builder.append(sub);
160        builder.append(aspect);
161        classes.add(builder.toString());
162      }
163    
164      public void addClasses(StyleClasses styleClasses) {
165        for (String clazz : (Iterable<String>) styleClasses.classes) {
166          classes.add(clazz);
167        }
168      }
169    
170      public void removeClass(String clazz) {
171        classes.remove(clazz);
172      }
173    
174      public void removeTobagoClasses(String rendererName) {
175        for (Iterator i = classes.iterator(); i.hasNext();) {
176          String clazz = (String) i.next();
177          if (clazz.startsWith(PREFIX + rendererName)) {
178            i.remove();
179          }
180        }
181      }
182    
183      public void updateClassAttribute(UIComponent component, String rendererName) {
184        // first remove old tobago-<rendererName>-<type> classes from class-attribute
185        removeTobagoClasses(rendererName);
186    
187        addAspectClass(rendererName, Aspect.DEFAULT);
188        if (ComponentUtil.getBooleanAttribute(component, ATTR_DISABLED)) {
189          addAspectClass(rendererName, Aspect.DISABLED);
190        }
191        if (ComponentUtil.getBooleanAttribute(component, ATTR_READONLY)) {
192          addAspectClass(rendererName, Aspect.READONLY);
193        }
194        if (ComponentUtil.getBooleanAttribute(component, ATTR_INLINE)) {
195          addAspectClass(rendererName, Aspect.INLINE);
196        }
197        if (component instanceof UIInput) {
198          UIInput input = (UIInput) component;
199          if (ComponentUtil.isError(input)) {
200            addAspectClass(rendererName, Aspect.ERROR);
201          }
202          if (input.isRequired()) {
203            addAspectClass(rendererName, Aspect.REQUIRED);
204          }
205        }
206    
207        addMarkupClass(component, rendererName);
208      }
209    
210      @Override
211      public String toString() {
212        StringBuffer buffer = new StringBuffer();
213        for (Iterator i = classes.iterator(); i.hasNext();) {
214          String clazz = (String) i.next();
215          buffer.append(clazz);
216          if (i.hasNext()) {
217            buffer.append(' ');
218          }
219        }
220        return buffer.toString();
221      }
222    
223      public enum Aspect {
224    
225        DEFAULT,
226        DISABLED,
227        READONLY,
228        INLINE,
229        ERROR,
230        REQUIRED;
231    
232        private String aspect;
233    
234        Aspect() {
235          aspect = '-' + name().toLowerCase();
236        }
237    
238        @Override
239        public String toString() {
240          return aspect;
241        }
242      }
243    }