package com.jotuntech.sketcher.common; import java.util.Collection; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * This map is for storing values with keys. A value can be located * with a key and vice versa. This class will assume that no mutations to the keys * are made. Values may implement Copyable to get included in copy() operations * performed on the map. * * @author Thor Harald Johansen * * @param Type of values this map will store */ public class TwoWayHashMap implements Map, Copyable> { private Map keyMap; private Map valueMap; private List changeListeners; private Integer autoKey; /** Create new integer map */ public TwoWayHashMap() { keyMap = new LinkedHashMap(); valueMap = new IdentityHashMap(); changeListeners = new LinkedList(); autoKey = new Integer(1); } @SuppressWarnings("unchecked") public TwoWayHashMap(TwoWayHashMap map) { keyMap = new LinkedHashMap(); valueMap = new IdentityHashMap(); changeListeners = new LinkedList(); autoKey = map.autoKey; for(Map.Entry e : map.keyMap.entrySet()) { if(e.getValue() instanceof Copyable) { put(e.getKey(), ((Copyable)e.getValue()).copy()); } else { put(e.getKey(), e.getValue()); } } } /** Insert value into map under specified key */ public V put(K key, V value) { /** Put key into key map, store old value */ V oldValue = keyMap.put(key, value); /** Remove old value from value map */ valueMap.remove(oldValue); /** Put value into value map */ valueMap.put(value, key); /** Notify change listener method */ change(); /** Return old value */ return oldValue; } /** Insert value into map and auto-assign key * * @return Auto-assigned key */ @SuppressWarnings("unchecked") public K put(V value) { /** Put value into map */ put((K) autoKey, value); /** Increment auto key and return previous one */ return (K) autoKey++; } /** Remove entry for specified key from map * * @return Entry that was removed, or null if no such entry. */ public V remove(Object key) { /** Remove key from key map, store old value */ V oldValue = keyMap.remove(key); /** Remove old value from value map */ valueMap.remove(oldValue); /** Notify change listener method */ change(); /** Return old value */ return oldValue; } /** Remove entry for specified value from map * * @return Key of entry that was removed, or null if no such entry. */ public K removeByValue(V value) { /** Remove old value from value map, store old key */ K oldKey = valueMap.remove(value); /** Remove old key from key map */ keyMap.remove(oldKey); /** Notify change listener method */ change(); /** Return old key */ return oldKey; } /** Get value for specified key */ public V get(Object key) { return keyMap.get(key); } /** Get key for specified value */ public K getKeyForValue(V value) { return valueMap.get(value); } /** Get entry set from map */ public Set> entrySet() { return keyMap.entrySet(); } /** Get set of keys from map */ public Set keySet() { return keyMap.keySet(); } /** Get collection of values from map */ public Collection values() { return keyMap.values(); } public void addChangeListener(ChangeListener l) { changeListeners.add(l); } /** Notify listeners of change to map */ public void change() { for(ChangeListener l : changeListeners) { l.stateChanged(new ChangeEvent(this)); } } public TwoWayHashMap copy() { return new TwoWayHashMap(this); } public void clear() { keyMap.clear(); valueMap.clear(); change(); } public void setNextKey(Integer nextKey) { this.autoKey = nextKey; } public Integer getNextKey() { return autoKey; } public boolean containsKey(Object key) { return keyMap.containsKey(key); } public boolean containsValue(Object value) { return valueMap.containsKey(value); } public boolean isEmpty() { return keyMap.isEmpty(); } public void putAll(Map m) { throw new UnsupportedOperationException(); } public int size() { return keyMap.size(); } }