001/*
002 * $Id: DefaultsList.java 4047 2011-07-19 18:51:12Z kschaefe $
003 * 
004 * Copyright 2007 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020 */
021package org.jdesktop.swingx.plaf;
022
023import java.awt.Color;
024import java.awt.Dimension;
025import java.awt.Font;
026import java.awt.Insets;
027import java.util.ArrayList;
028import java.util.List;
029
030import javax.swing.ActionMap;
031import javax.swing.Icon;
032import javax.swing.InputMap;
033import javax.swing.border.Border;
034import javax.swing.plaf.UIResource;
035
036import org.jdesktop.swingx.painter.Painter;
037//import org.jdesktop.swingx.renderer.StringValue;
038import org.jdesktop.swingx.util.Contract;
039
040/**
041 * A specialty "list" for working with UI defaults. Requires adds to be done
042 * using key/value pairs. The purpose of this list is to enforce additions as
043 * pairs.
044 * 
045 * @author Karl George Schaefer
046 */
047@SuppressWarnings("nls")
048public final class DefaultsList {
049    private List<Object> delegate;
050
051    /**
052     * Creates a {@code DefaultsList}.
053     */
054    public DefaultsList() {
055        delegate = new ArrayList<Object>();
056    }
057
058    /**
059     * Adds a key/value pair to the defaults list. This implementation defers to
060     * {@link #add(Object, Object, boolean)} with {@code enableChecking} set to
061     * {@code true}.
062     * 
063     * @param key
064     *                the key that will be used to query {@code UIDefaults}
065     * @param value
066     *                the value associated with the key
067     * @throws NullPointerException
068     *                 if {@code key} is {@code null}
069     * @throws IllegalArgumentException
070     *                 if {@code value} is a type that should be a
071     *                 {@code UIResource} but is not. For instance, passing in a
072     *                 {@code Border} that is not a {@code UIResource} will
073     *                 cause an exception. This checking must be enabled.
074     */
075    public void add(Object key, Object value) {
076        add(key, value, true);
077    }
078
079    /**
080     * Adds a key/value pair to the defaults list. A pair with a {@code null}
081     * value is treated specially. A {@code null}-value pair is never added to
082     * the list and, furthermore, if a key/value pair exists in this list with
083     * the same key as the newly added one, it is removed.
084     * 
085     * @param key
086     *                the key that will be used to query {@code UIDefaults}
087     * @param value
088     *                the value associated with the key
089     * @param enableChecking
090     *                if {@code true} then the value is checked to ensure that
091     *                it is a {@code UIResource}, if appropriate
092     * @throws NullPointerException
093     *                 if {@code key} is {@code null}
094     * @throws IllegalArgumentException
095     *                 if {@code value} is a type that should be a
096     *                 {@code UIResource} but is not. For instance, passing in a
097     *                 {@code Border} that is not a {@code UIResource} will
098     *                 cause an exception. This checking must be enabled.
099     */
100    public void add(Object key, Object value, boolean enableChecking) {
101        if (enableChecking) {
102            asUIResource(value, value + " must be a UIResource");
103        }
104        
105        if (value == null && delegate.contains(key)) {
106            int i = delegate.indexOf(key);
107            
108            delegate.remove(i + 1);
109            delegate.remove(i);
110        } else if (value != null) {
111            delegate.add(Contract.asNotNull(key, "key cannot be null"));
112            delegate.add(value);
113        }
114    }
115    
116    //TODO move to Contract?
117    private static <T> T asUIResource(T value, String message) {
118        if (!(value instanceof UIResource)) {
119            boolean shouldThrow = false;
120            
121            shouldThrow |= value instanceof ActionMap;
122            shouldThrow |= value instanceof Border;
123            shouldThrow |= value instanceof Color;
124            shouldThrow |= value instanceof Dimension;
125            shouldThrow |= value instanceof Font;
126            shouldThrow |= value instanceof Icon;
127            shouldThrow |= value instanceof InputMap;
128            shouldThrow |= value instanceof Insets;
129            shouldThrow |= value instanceof Painter<?>;
130            //FIXME how to handle UIResource testing
131//            shouldThrow |= value instanceof StringValue;
132            
133            if (shouldThrow) {
134                throw new IllegalArgumentException(message);
135            }
136        }
137        
138        return value;
139    }
140    
141    /**
142     * Gets a copy of this list as an array.
143     * 
144     * @return an array containing all of the key/value pairs added to this list
145     */
146    public Object[] toArray() {
147        return delegate.toArray();
148    }
149}