org.wings.plaf.LookAndFeel.java Source code

Java tutorial

Introduction

Here is the source code for org.wings.plaf.LookAndFeel.java

Source

/*
 * $Id$
 * Copyright 2000,2005 wingS development team.
 *
 * This file is part of wingS (http://www.j-wings.org).
 *
 * wingS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * Please see COPYING for the complete licence.
 */
package org.wings.plaf;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wings.Resource;
import org.wings.SDimension;
import org.wings.SIcon;
import org.wings.SResourceIcon;
import org.wings.resource.ClasspathResource;
import org.wings.style.CSSAttributeSet;
import org.wings.style.CSSStyleSheet;
import org.wings.style.StyleSheet;
import org.wings.style.CSSProperty;

import java.awt.*;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.*;

/**
 * A Look-and-Feel consists of a bunch of CGs and resource properties.
 * wingS provides a pluggable look-and-feel (laf or plaf) concept similar to that of Swing.
 * A certain plaf implementation normally adresses a specific browser platform.
 *
 * @see org.wings.plaf.ComponentCG
 */
public class LookAndFeel implements Serializable {
    private final transient static Log log = LogFactory.getLog(LookAndFeel.class);

    private static Map wrappers = new HashMap();
    static {
        wrappers.put(Boolean.TYPE, Boolean.class);
        wrappers.put(Character.TYPE, Character.class);
        wrappers.put(Byte.TYPE, Byte.class);
        wrappers.put(Short.TYPE, Short.class);
        wrappers.put(Integer.TYPE, Integer.class);
        wrappers.put(Long.TYPE, Long.class);
        wrappers.put(Float.TYPE, Float.class);
        wrappers.put(Double.TYPE, Double.class);
    }

    protected Properties properties;

    private static final Map finalResources = Collections.synchronizedMap(new HashMap());

    /**
     * Instantiate a laf using the war's classLoader.
     *
     * @param properties the configuration of the laf
     */
    public LookAndFeel(Properties properties) {
        this.properties = properties;
    }

    /**
     * Return a unique string that identifies this look and feel, e.g.
     * "konqueror"
     */
    public String getName() {
        return properties.getProperty("lookandfeel.name");
    }

    /**
     * Return a one line description of this look and feel implementation,
     * e.g. "Optimized for KDE's Konqueror Browser".
     */
    public String getDescription() {
        return properties.getProperty("lookandfeel.description");
    }

    /**
     * create a fresh CGDefaults map. One defaults map per Session is generated
     * in its CGManager. It is necessary to create a fresh defaults map, since
     * it caches values that might be modified within the sessions. A prominent
     * example of changed values per sessions are the CG's themselves:
     * CG-properties might be changed per session...
     *
     * @return the laf's defaults
     */
    public CGDefaults createDefaults() {
        return new ResourceFactory();
    }

    /**
     * Create a CG instance.
     *
     * @param className the full qualified class name of the CG
     * @return a new CG instance
     */
    public static Object makeCG(String className) {
        Object result = finalResources.get(className);
        if (result == null) {
            try {
                Class cgClass = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
                result = cgClass.newInstance();
                finalResources.put(className, result);
            } catch (Exception ex) {
                log.fatal(null, ex);
            }
        }
        return result;
        /* changed this method due to NoClassDefFoundError at Tomcat startup.
         * see http://sourceforge.net/mailarchive/forum.php?thread_id=7551328&forum_id=13034
         */
        //        Object result = null;
        //        try {
        //            Class cgClass = Class.forName(className, true, Thread
        //                    .currentThread().getContextClassLoader());
        //            result = cgClass.newInstance();
        //            finalResources.put(className, result);
        //        } catch (Exception ex) {
        //            log.fatal(null, ex);
        //        }
        //        return result;
    }

    /**
     * Utility method that creates an java.awt.Color from a html color hex string
     *
     * @return the create color
     */
    public static Color makeColor(String colorString) {
        if (colorString != null) {
            try {
                return Color.decode(colorString.trim());
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
        return null;
    }

    /**
     * Utility method that creates a dimension from a dimension string separated by comma 
     *
     * @return the create color
     */
    public static SDimension makeDimension(String dimensionString) {
        if (dimensionString != null) {
            int commaIndex = dimensionString.indexOf(',');
            if (commaIndex > 0) {
                return new SDimension(dimensionString.substring(0, commaIndex),
                        dimensionString.substring(commaIndex + 1));
            }
        }
        return null;
    }

    /**
     * Utility method that creates an Icon from a resource
     * located realtive to the given base class. Uses the ClassLoader
     * of the LookAndFeel
     *
     * @param fileName of the image file
     * @return a newly allocated Icon
     */
    public static SIcon makeIcon(String fileName) {
        SIcon result = (SIcon) finalResources.get(fileName);
        if (result == null) {
            result = new SResourceIcon(fileName);
            finalResources.put(fileName, result);
        }
        return result;
    }

    /**
     * Utility method that creates an CSSPropertySet from a String
     *
     * @param string attributes string
     * @return a newly allocated CSSPropertySet
     */
    public static CSSAttributeSet makeAttributeSet(String string) {
        CSSAttributeSet attributes = new CSSAttributeSet();
        StringTokenizer tokens = new StringTokenizer(string, ";");
        while (tokens.hasMoreTokens()) {
            String token = tokens.nextToken();
            int pos = token.indexOf(":");
            if (pos >= 0) {
                attributes.put(new CSSProperty(token.substring(0, pos)), token.substring(pos + 1));
            }
        }
        return attributes;
    }

    /**
     * Utility method that creates a styleSheet from a string
     *
     * @param resourceName styleSheet as a string
     * @return the styleSheet
     */
    public static Resource makeResource(String resourceName) {
        Resource result = (Resource) finalResources.get(resourceName);
        if (result == null) {
            result = new ClasspathResource(resourceName);
            finalResources.put(resourceName, result);
        }
        return result;
    }

    /**
     * Utility method that creates a stylesheet object from a resource
     *
     * @return the styleSheet
     */
    public static StyleSheet makeStyleSheet(String resourceName) {
        try {
            CSSStyleSheet result = new CSSStyleSheet();
            InputStream in = LookAndFeel.class.getClassLoader().getResourceAsStream(resourceName);
            result.read(in);
            in.close();
            return result;
        } catch (Exception e) {
            log.warn("Exception", e);
        }
        return null;
    }

    /**
     * Utility method that creates an Object of class <code>clazz</code>
     * using the single String arg constructor.
     *
     * @param value object as a string
     * @param clazz class of the object
     * @return the object
     */
    public static Object makeObject(String value, Class clazz) {
        Object result;
        try {
            if (value.startsWith("new ")) {
                int bracket = value.indexOf("(");
                String name = value.substring("new ".length(), bracket);
                clazz = Class.forName(name, true, Thread.currentThread().getContextClassLoader());
                result = clazz.newInstance();
            } else {
                if (clazz.isPrimitive())
                    clazz = (Class) wrappers.get(clazz);
                Constructor constructor = clazz.getConstructor(new Class[] { String.class });
                result = constructor.newInstance(new Object[] { value });
            }
        } catch (NoSuchMethodException e) {
            log.fatal(value + " : " + clazz.getName() + " doesn't have a single String arg constructor", e);
            result = null;
        } catch (Exception e) {
            log.error(e.getClass().getName() + " : " + value, e);
            result = null;
        }
        return result;
    }

    /**
     * Returns a string that displays and identifies this
     * object's properties.
     *
     * @return a String representation of this object
     */
    public String toString() {
        return "[" + getDescription() + " - " + getClass().getName() + "]";
    }

    class ResourceFactory extends CGDefaults {

        public ResourceFactory() {
            super(null);
        }

        public Object get(Object key, Class type) {
            Object value = get(key);
            if (value != null)
                return value;

            String property;
            if (key instanceof Class) {
                Class clazz = (Class) key;
                do {
                    property = properties.getProperty(clazz.getName());
                    clazz = clazz.getSuperclass();
                } while (property == null && clazz != null);
            } else
                property = properties.getProperty(key.toString());

            if (property == null) {
                put(key, null);
                return null;
            }

            if (ComponentCG.class.isAssignableFrom(type) || LayoutCG.class.isAssignableFrom(type)
                    || PrefixAndSuffixDelegate.class.isAssignableFrom(type))
                value = makeCG(property);
            else if (type.isAssignableFrom(SIcon.class))
                value = makeIcon(property);
            else if (type.isAssignableFrom(Resource.class))
                value = makeResource(property);
            else if (type.isAssignableFrom(CSSAttributeSet.class))
                value = makeAttributeSet(property);
            else if (type.isAssignableFrom(StyleSheet.class))
                value = makeStyleSheet(property);
            else if (type.isAssignableFrom(Color.class))
                value = makeColor(property);
            else if (type.isAssignableFrom(SDimension.class))
                value = makeDimension(property);
            else
                value = makeObject(property, type);

            put(key, value);
            return value;
        }
    }
}