com.googlecode.blaisemath.style.AttributeSet Maven / Gradle / Ivy
/**
* StyleAttributes.java
* Created Jul 31, 2014
*/
package com.googlecode.blaisemath.style;
/*
* #%L
* BlaiseGraphics
* --
* Copyright (C) 2009 - 2015 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.Map;
import java.util.Set;
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.
*
* @author Elisha
*/
public class AttributeSet implements Cloneable {
/** Constant representing the empty attribute set */
public static final AttributeSet EMPTY = new ImmutableAttributeSet();
/** The parent attribute set */
protected Optional parent;
/** The map of style key/value pairs */
protected final Map attributeMap = Maps.newHashMap();
private transient final ChangeEvent changeEvent = new ChangeEvent(this);
private transient final EventListenerList listenerList = new EventListenerList();
public AttributeSet() {
this.parent = Optional.absent();
}
public AttributeSet(@Nullable AttributeSet parent) {
this.parent = Optional.fromNullable(parent);
}
@Override
protected AttributeSet clone() {
AttributeSet res = new AttributeSet(parent.orNull());
res.attributeMap.putAll(attributeMap);
return res;
}
@Override
public String toString() {
return "AttributeSet " + attributeMap;
}
//
/**
* Generate attribute set with given key/value pair
* @param par the parent
* @return created set
*/
public static AttributeSet withParent(AttributeSet par) {
return new AttributeSet(par);
}
/**
* Generate attribute set with given key/value pair
* @param key the key
* @param val the value
* @return created set
*/
public static AttributeSet with(String key, Object val) {
AttributeSet res = new AttributeSet();
res.put(key, val);
return res;
}
/**
* Builder pattern for setting a key/value pair
* @param key the key
* @param val the value
* @return this object
*/
public AttributeSet and(String key, Object val) {
put(key, val);
return this;
}
/**
* Wraps 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.copyOf(this);
}
/**
* Creates a copy of the attribute set.
* @return copy
*/
public AttributeSet copy() {
AttributeSet res = new AttributeSet(parent.orNull());
for (String k : attributeMap.keySet()) {
res.put(k, copyValue(get(k)));
}
return res;
}
/**
* Creates a copy of the attribute set, including all parent attributes
* @return copy
*/
public AttributeSet flatCopy() {
AttributeSet res = new AttributeSet();
for (String k : getAllAttributes()) {
res.put(k, copyValue(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;
}
}
//
//
//
// 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) {
throw new ClassCastException("Cast from "+get(key)+" to "+cls+" failed.");
}
}
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