All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.blaisemath.style.AttributeSet Maven / Gradle / Ivy

/**
 * AttributeSet.java
 * Created Jul 31, 2014
 */
package com.googlecode.blaisemath.style;

/*
 * #%L
 * BlaiseGraphics
 * --
 * Copyright (C) 2014 - 2017 Elisha Peterson
 * --
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */


import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.awt.Color;
import java.awt.geom.Point2D;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;

/**
 * Provides a map of key-value pairs providing style elements, similar to what
 * one finds in CSS style attributes. Values are allowed to be null.
 * 
 * @author Elisha
 */
public class AttributeSet {
    
    private static final Logger LOG = Logger.getLogger(AttributeSet.class.getName());
    
    /** Constant representing the empty attribute set */
    public static final AttributeSet EMPTY = ImmutableAttributeSet.copyOf(new AttributeSet());
    
    /** The parent attribute set */
    protected Optional parent = Optional.absent();
    /** The map of style key/value pairs */
    protected final Map attributeMap = Maps.newHashMap();
    
    private final transient ChangeEvent changeEvent = new ChangeEvent(this);
    private final transient EventListenerList listenerList = new EventListenerList();

    @Override
    public String toString() {
        return "AttributeSet " + attributeMap;
    }

    //
    
    /**
     * Create new attribute set with elements of given map.
     * @param map key-value map
     * @return new attribute set
     */
    public static AttributeSet create(Map map) {
        AttributeSet res = new AttributeSet();
        res.putAll(map);
        return res;
    }
    
    /** 
     * Create new attribute set with given parent.
     * @param parent the parent
     * @return new attribute set
     */
    public static AttributeSet createWithParent(@Nullable AttributeSet parent) {
        AttributeSet res = new AttributeSet();
        res.parent = Optional.fromNullable(parent);
        return res;
    }
    
    /** 
     * Create copy of attribute set, with all values copies as well.
     * @param set to copy
     * @return copy
     */
    public static AttributeSet copyOf(AttributeSet set) {
        AttributeSet res = createWithParent(set.getParent());
        for (String k : set.getAttributeMap().keySet()) {
            res.put(k, copyValue(set.get(k)));
        }
        return res;
    }
    
    /** 
     * Create flat copy of attribute set, with all values copies as well.
     * The resulting set has no parent attribute set.
     * @param set to copy
     * @return copy
     */
    public static AttributeSet flatCopyOf(AttributeSet set) {
        AttributeSet res = new AttributeSet();
        for (String k : set.getAllAttributes()) {
            res.put(k, copyValue(set.get(k)));
        }
        return res;
    }

    /**
     * Create a partial copy of the attribute set, with only those values matching
     * the given keys.
     * @param sty style to copy from
     * @param keys keys to copy
     * @return copied style
     */
    public static AttributeSet copy(AttributeSet sty, String... keys) {
        AttributeSet res = new AttributeSet();
        for (String k : keys) {
            if (sty.contains(k)) {
                res.put(k, sty.get(k));
            }
        }
        return res;
    }
    
    /**
     * Copies a value in an attribute set, returning a new instance if the value
     * is not an immutable object.
     * @param 

value type * @param val value to copy * @return new value instance */ private static

P copyValue(P val) { if (val instanceof Point2D) { return (P) ((Point2D)val).clone(); } else { return val; } } /** * Generate attribute set with given key/value pair * @param k1 the key * @param v1 the value * @return created set */ public static AttributeSet of(String k1, @Nullable Object v1) { return create(Collections.singletonMap(k1, v1)); } /** * Generate attribute set with given key/value pairs. * @param k1 first key * @param v1 first value * @param k2 second key * @param v2 second value * @return created set */ public static AttributeSet of(String k1, @Nullable Object v1, String k2, @Nullable Object v2) { return of(k1, v1).and(k2, v2); } /** * Generate attribute set with given key/value pairs. * @param k1 first key * @param v1 first value * @param k2 second key * @param v2 second value * @param k3 third key * @param v3 third value * @return created set */ public static AttributeSet of(String k1, @Nullable Object v1, String k2, @Nullable Object v2, String k3, @Nullable Object v3) { return of(k1, v1).and(k2, v2).and(k3, v3); } // // /** * Builder pattern for setting a key/value pair * @param key the key * @param val the value * @return this object */ public AttributeSet and(String key, @Nullable Object val) { put(key, val); return this; } /** * Copies the attribute set as an unmodifiable object, which will throw errors * if any of its get/put methods are accessed. * @return immutable set with all the attributes of this one */ public AttributeSet immutable() { return ImmutableAttributeSet.immutableCopyOf(this); } /** * Copies the attribute set as an unmodifiable object, which will throw errors * if any of its get/put methods are accessed. * @param par parent to use for copy * @return immutable set with all the attributes of this one */ public AttributeSet immutableWithParent(AttributeSet par) { return ImmutableAttributeSet.immutableCopyOf(this, par); } /** * Creates a copy of the attribute set. * @return copy */ public AttributeSet copy() { return copyOf(this); } /** * Creates a copy of the attribute set, including all parent attributes * @return copy */ public AttributeSet flatCopy() { return flatCopyOf(this); } // // // // PROPERTY PATTERNS // @Nullable public AttributeSet getParent() { return parent.orNull(); } // // // // GENERIC ATTRIBUTE METHODS // /** * Get the set of attributes known in this set. * @return attribute keys */ public Set getAttributes() { return attributeMap.keySet(); } /** * Get the attributes and the values in this set as a map * @return attribute map */ public Map getAttributeMap() { return Maps.newHashMap(attributeMap); } /** * Get this attributes, and all parent attributes. * @return attribute keys */ public Set getAllAttributes() { if (parent.isPresent()) { return Sets.union(attributeMap.keySet(), parent.get().getAllAttributes()); } else { return getAttributes(); } } /** * Return attributes of the given type, whether in this set or the parent set. * @param type attribute type * @return attribute keys */ public Set getAllAttributes(Class type) { Map filtered = Maps.filterValues(attributeMap, Predicates.instanceOf(type)); if (parent.isPresent()) { return Sets.union(filtered.keySet(), parent.get().getAllAttributes(type)); } else { return filtered.keySet(); } } /** * Return true if this set or its ancestors contain the given key. * @param key attribute key * @return true if attribute is accessible from this set */ public boolean contains(String key) { return attributeMap.containsKey(key) || (parent.isPresent() && parent.get().contains(key)); } /** * Get the given attribute. * @param key the key * @return value of the found attribute, either contained in this set or its parent, * or null if there is none */ @Nullable public Object get(String key) { if (attributeMap.containsKey(key)) { return attributeMap.get(key); } else if (parent.isPresent()) { return parent.get().get(key); } else { return null; } } /** * Get the given attribute. * @param key the key * @param value the attribute value (may be null) * @return the old value */ @Nullable public Object put(String key, @Nullable Object value) { Object res = attributeMap.put(key, value); fireStateChanged(); return res; } /** * Set all of the attributes in the provided map. * @param attr map of attributes to set * @param the type of values in the map */ public void putAll(Map attr) { attributeMap.putAll(attr); fireStateChanged(); } /** * Remove attribute with the given key. * @param key the key * @return the removed value, null if none */ public Object remove(String key) { Object res = attributeMap.remove(key); fireStateChanged(); return res; } // // @Nullable private C getTyped(String key, Class cls, @Nullable C def) { try { return cls.cast(contains(key) ? (C) get(key) : def); } catch (ClassCastException x) { LOG.log(Level.WARNING, "Cast from "+get(key)+" to "+cls+" failed.", x); throw x; } } public String getString(String key) { return getTyped(key, String.class, null); } public String getString(String key, String def) { return getTyped(key, String.class, def); } /** * Retrieve given attribute as a color. * @param key attribute key * @return color, or null if not present * @throws ClassCastException if attribute is present but not a color */ @Nullable public Color getColor(String key) { return getTyped(key, Color.class, null); } @Nullable public Color getColor(String key, @Nullable Color def) { return getTyped(key, Color.class, def); } @Nullable public Point2D getPoint(String key) { return getTyped(key, Point2D.class, null); } @Nullable public Point2D getPoint(String key, @Nullable Point2D def) { return getTyped(key, Point2D.class, def); } /** * Get the boolean value associated with the key * @param key key * @return boolean value, or null if there is none */ @Nullable public Boolean getBoolean(String key) { return getTyped(key, Boolean.class, null); } /** * Get the boolean value associated with the key. * @param key key * @param def default value * @return boolean value, or def if there is none */ @Nullable public Boolean getBoolean(String key, @Nullable Boolean def) { try { return getTyped(key, Boolean.class, def); } catch (ClassCastException x) { return get(key) instanceof String ? Boolean.valueOf((String) get(key)) : false; } } /** * Retrieve given attribute as a float. * @param key attribute key * @return float, or null if not present * @throws ClassCastException if attribute is present but not a float */ @Nullable public Float getFloat(String key) { return getFloat(key, null); } @Nullable public Float getFloat(String key, @Nullable Float def) { if (contains(key)) { Number n = (Number) get(key); return n == null ? null : n instanceof Float ? (Float) n : n.floatValue(); } else { return def; } } @Nullable public Integer getInteger(String key) { return getInteger(key, null); } @Nullable public Integer getInteger(String key, @Nullable Integer def) { if (contains(key)) { Number n = (Number) get(key); return n == null ? null : n instanceof Integer ? (Integer) n : n.intValue(); } else { return def; } } // // // // EVENT HANDLING // public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); } public void removeChangeListener(ChangeListener l) { listenerList.remove(ChangeListener.class, l); } /** Notify interested listeners of an (unspecified) change in the plottable. */ public void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { if (changeEvent == null) { return; } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } // }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy