001    /*
002     * $Id: DefaultsList.java 2668 2008-02-06 04:19:28Z 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     */
021    package org.jdesktop.swingx.plaf;
022    
023    import java.awt.Color;
024    import java.awt.Dimension;
025    import java.awt.Font;
026    import java.awt.Insets;
027    import java.util.ArrayList;
028    import java.util.List;
029    
030    import javax.swing.ActionMap;
031    import javax.swing.Icon;
032    import javax.swing.InputMap;
033    import javax.swing.border.Border;
034    import javax.swing.plaf.UIResource;
035    
036    import org.jdesktop.swingx.painter.Painter;
037    import org.jdesktop.swingx.util.Contract;
038    
039    /**
040     * A specialty "list" for working with UI defaults. Requires adds to be done
041     * using key/value pairs. The purpose of this list is to enforce additions as
042     * pairs.
043     * 
044     * @author Karl George Schaefer
045     */
046    public final class DefaultsList {
047        private List<Object> delegate;
048    
049        /**
050         * Creates a {@code DefaultsList}.
051         */
052        public DefaultsList() {
053            delegate = new ArrayList<Object>();
054        }
055    
056        /**
057         * Adds a key/value pair to the defaults list. This implementation defers to
058         * {@link #add(Object, Object, boolean)} with {@code enableChecking} set to
059         * {@code true}.
060         * 
061         * @param key
062         *                the key that will be used to query {@code UIDefaults}
063         * @param value
064         *                the value associated with the key
065         * @throws NullPointerException
066         *                 if {@code key} is {@code null}
067         * @throws IllegalArgumentException
068         *                 if {@code value} is a type that should be a
069         *                 {@code UIResource} but is not. For instance, passing in a
070         *                 {@code Border} that is not a {@code UIResource} will
071         *                 cause an exception. This checking must be enabled.
072         */
073        public void add(Object key, Object value) {
074            add(key, value, true);
075        }
076    
077        /**
078         * Adds a key/value pair to the defaults list. A pair with a {@code null}
079         * value is treated specially. A {@code null}-value pair is never added to
080         * the list and, furthermore, if a key/value pair exists in this list with
081         * the same key as the newly added one, it is removed.
082         * 
083         * @param key
084         *                the key that will be used to query {@code UIDefaults}
085         * @param value
086         *                the value associated with the key
087         * @param enableChecking
088         *                if {@code true} then the value is checked to ensure that
089         *                it is a {@code UIResource}, if appropriate
090         * @throws NullPointerException
091         *                 if {@code key} is {@code null}
092         * @throws IllegalArgumentException
093         *                 if {@code value} is a type that should be a
094         *                 {@code UIResource} but is not. For instance, passing in a
095         *                 {@code Border} that is not a {@code UIResource} will
096         *                 cause an exception. This checking must be enabled.
097         */
098        public void add(Object key, Object value, boolean enableChecking) {
099            if (enableChecking) {
100                asUIResource(value, value + " must be a UIResource");
101            }
102            
103            if (value == null && delegate.contains(key)) {
104                int i = delegate.indexOf(key);
105                
106                delegate.remove(i + 1);
107                delegate.remove(i);
108            } else if (value != null) {
109                delegate.add(Contract.asNotNull(key, "key cannot be null"));
110                delegate.add(value);
111            }
112        }
113        
114        //TODO move to Contract?
115        private static <T> T asUIResource(T value, String message) {
116            if (!(value instanceof UIResource)) {
117                boolean shouldThrow = false;
118                
119                shouldThrow |= value instanceof ActionMap;
120                shouldThrow |= value instanceof Border;
121                shouldThrow |= value instanceof Color;
122                shouldThrow |= value instanceof Dimension;
123                shouldThrow |= value instanceof Font;
124                shouldThrow |= value instanceof Icon;
125                shouldThrow |= value instanceof InputMap;
126                shouldThrow |= value instanceof Insets;
127                shouldThrow |= value instanceof Painter;
128                
129                if (shouldThrow) {
130                    throw new IllegalArgumentException(message);
131                }
132            }
133            
134            return value;
135        }
136        
137        /**
138         * Gets a copy of this list as an array.
139         * 
140         * @return an array containing all of the key/value pairs added to this list
141         */
142        public Object[] toArray() {
143            return delegate.toArray();
144        }
145    }