0N/A/*
2362N/A * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage javax.swing;
0N/A
0N/Aimport java.io.IOException;
0N/Aimport java.io.ObjectOutputStream;
0N/Aimport java.io.Serializable;
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.Hashtable;
0N/A
0N/A/*
0N/A * Private storage mechanism for Action key-value pairs.
0N/A * In most cases this will be an array of alternating
0N/A * key-value pairs. As it grows larger it is scaled
0N/A * up to a Hashtable.
0N/A * <p>
0N/A * This does no synchronization, if you need thread safety synchronize on
0N/A * another object before calling this.
0N/A *
0N/A * @author Georges Saab
0N/A * @author Scott Violet
0N/A */
0N/Aclass ArrayTable implements Cloneable {
0N/A // Our field for storage
0N/A private Object table = null;
0N/A private static final int ARRAY_BOUNDARY = 8;
0N/A
0N/A
0N/A /**
0N/A * Writes the passed in ArrayTable to the passed in ObjectOutputStream.
0N/A * The data is saved as an integer indicating how many key/value
0N/A * pairs are being archived, followed by the the key/value pairs. If
0N/A * <code>table</code> is null, 0 will be written to <code>s</code>.
0N/A * <p>
0N/A * This is a convenience method that ActionMap/InputMap and
0N/A * AbstractAction use to avoid having the same code in each class.
0N/A */
0N/A static void writeArrayTable(ObjectOutputStream s, ArrayTable table) throws IOException {
0N/A Object keys[];
0N/A
0N/A if (table == null || (keys = table.getKeys(null)) == null) {
0N/A s.writeInt(0);
0N/A }
0N/A else {
0N/A // Determine how many keys have Serializable values, when
0N/A // done all non-null values in keys identify the Serializable
0N/A // values.
0N/A int validCount = 0;
0N/A
0N/A for (int counter = 0; counter < keys.length; counter++) {
0N/A Object key = keys[counter];
0N/A
0N/A /* include in Serialization when both keys and values are Serializable */
0N/A if ( (key instanceof Serializable
0N/A && table.get(key) instanceof Serializable)
0N/A ||
0N/A /* include these only so that we get the appropriate exception below */
0N/A (key instanceof ClientPropertyKey
0N/A && ((ClientPropertyKey)key).getReportValueNotSerializable())) {
0N/A
0N/A validCount++;
0N/A } else {
0N/A keys[counter] = null;
0N/A }
0N/A }
0N/A // Write ou the Serializable key/value pairs.
0N/A s.writeInt(validCount);
0N/A if (validCount > 0) {
625N/A for (Object key : keys) {
625N/A if (key != null) {
625N/A s.writeObject(key);
625N/A s.writeObject(table.get(key));
0N/A if (--validCount == 0) {
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Put the key-value pair into storage
0N/A */
0N/A public void put(Object key, Object value){
0N/A if (table==null) {
0N/A table = new Object[] {key, value};
0N/A } else {
0N/A int size = size();
0N/A if (size < ARRAY_BOUNDARY) { // We are an array
0N/A if (containsKey(key)) {
0N/A Object[] tmp = (Object[])table;
0N/A for (int i = 0; i<tmp.length-1; i+=2) {
0N/A if (tmp[i].equals(key)) {
0N/A tmp[i+1]=value;
0N/A break;
0N/A }
0N/A }
0N/A } else {
0N/A Object[] array = (Object[])table;
0N/A int i = array.length;
0N/A Object[] tmp = new Object[i+2];
0N/A System.arraycopy(array, 0, tmp, 0, i);
0N/A
0N/A tmp[i] = key;
0N/A tmp[i+1] = value;
0N/A table = tmp;
0N/A }
0N/A } else { // We are a hashtable
0N/A if ((size==ARRAY_BOUNDARY) && isArray()) {
0N/A grow();
0N/A }
0N/A ((Hashtable)table).put(key, value);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Gets the value for key
0N/A */
0N/A public Object get(Object key) {
0N/A Object value = null;
0N/A if (table !=null) {
0N/A if (isArray()) {
0N/A Object[] array = (Object[])table;
0N/A for (int i = 0; i<array.length-1; i+=2) {
0N/A if (array[i].equals(key)) {
0N/A value = array[i+1];
0N/A break;
0N/A }
0N/A }
0N/A } else {
0N/A value = ((Hashtable)table).get(key);
0N/A }
0N/A }
0N/A return value;
0N/A }
0N/A
0N/A /*
0N/A * Returns the number of pairs in storage
0N/A */
0N/A public int size() {
0N/A int size;
0N/A if (table==null)
0N/A return 0;
0N/A if (isArray()) {
0N/A size = ((Object[])table).length/2;
0N/A } else {
0N/A size = ((Hashtable)table).size();
0N/A }
0N/A return size;
0N/A }
0N/A
0N/A /*
0N/A * Returns true if we have a value for the key
0N/A */
0N/A public boolean containsKey(Object key) {
0N/A boolean contains = false;
0N/A if (table !=null) {
0N/A if (isArray()) {
0N/A Object[] array = (Object[])table;
0N/A for (int i = 0; i<array.length-1; i+=2) {
0N/A if (array[i].equals(key)) {
0N/A contains = true;
0N/A break;
0N/A }
0N/A }
0N/A } else {
0N/A contains = ((Hashtable)table).containsKey(key);
0N/A }
0N/A }
0N/A return contains;
0N/A }
0N/A
0N/A /*
0N/A * Removes the key and its value
0N/A * Returns the value for the pair removed
0N/A */
0N/A public Object remove(Object key){
0N/A Object value = null;
0N/A if (key==null) {
0N/A return null;
0N/A }
0N/A if (table !=null) {
0N/A if (isArray()){
0N/A // Is key on the list?
0N/A int index = -1;
0N/A Object[] array = (Object[])table;
0N/A for (int i = array.length-2; i>=0; i-=2) {
0N/A if (array[i].equals(key)) {
0N/A index = i;
0N/A value = array[i+1];
0N/A break;
0N/A }
0N/A }
0N/A
0N/A // If so, remove it
0N/A if (index != -1) {
0N/A Object[] tmp = new Object[array.length-2];
0N/A // Copy the list up to index
0N/A System.arraycopy(array, 0, tmp, 0, index);
0N/A // Copy from two past the index, up to
0N/A // the end of tmp (which is two elements
0N/A // shorter than the old list)
0N/A if (index < tmp.length)
0N/A System.arraycopy(array, index+2, tmp, index,
0N/A tmp.length - index);
0N/A // set the listener array to the new array or null
0N/A table = (tmp.length == 0) ? null : tmp;
0N/A }
0N/A } else {
0N/A value = ((Hashtable)table).remove(key);
0N/A }
0N/A if (size()==ARRAY_BOUNDARY - 1 && !isArray()) {
0N/A shrink();
0N/A }
0N/A }
0N/A return value;
0N/A }
0N/A
0N/A /**
0N/A * Removes all the mappings.
0N/A */
0N/A public void clear() {
0N/A table = null;
0N/A }
0N/A
0N/A /*
0N/A * Returns a clone of the <code>ArrayTable</code>.
0N/A */
0N/A public Object clone() {
0N/A ArrayTable newArrayTable = new ArrayTable();
0N/A if (isArray()) {
0N/A Object[] array = (Object[])table;
0N/A for (int i = 0 ;i < array.length-1 ; i+=2) {
0N/A newArrayTable.put(array[i], array[i+1]);
0N/A }
0N/A } else {
0N/A Hashtable tmp = (Hashtable)table;
0N/A Enumeration keys = tmp.keys();
0N/A while (keys.hasMoreElements()) {
0N/A Object o = keys.nextElement();
0N/A newArrayTable.put(o,tmp.get(o));
0N/A }
0N/A }
0N/A return newArrayTable;
0N/A }
0N/A
0N/A /**
0N/A * Returns the keys of the table, or <code>null</code> if there
0N/A * are currently no bindings.
0N/A * @param keys array of keys
0N/A * @return an array of bindings
0N/A */
0N/A public Object[] getKeys(Object[] keys) {
0N/A if (table == null) {
0N/A return null;
0N/A }
0N/A if (isArray()) {
0N/A Object[] array = (Object[])table;
0N/A if (keys == null) {
0N/A keys = new Object[array.length / 2];
0N/A }
0N/A for (int i = 0, index = 0 ;i < array.length-1 ; i+=2,
0N/A index++) {
0N/A keys[index] = array[i];
0N/A }
0N/A } else {
0N/A Hashtable tmp = (Hashtable)table;
0N/A Enumeration enum_ = tmp.keys();
0N/A int counter = tmp.size();
0N/A if (keys == null) {
0N/A keys = new Object[counter];
0N/A }
0N/A while (counter > 0) {
0N/A keys[--counter] = enum_.nextElement();
0N/A }
0N/A }
0N/A return keys;
0N/A }
0N/A
0N/A /*
0N/A * Returns true if the current storage mechanism is
0N/A * an array of alternating key-value pairs.
0N/A */
0N/A private boolean isArray(){
0N/A return (table instanceof Object[]);
0N/A }
0N/A
0N/A /*
0N/A * Grows the storage from an array to a hashtable.
0N/A */
0N/A private void grow() {
0N/A Object[] array = (Object[])table;
625N/A Hashtable<Object, Object> tmp = new Hashtable<Object, Object>(array.length/2);
0N/A for (int i = 0; i<array.length; i+=2) {
0N/A tmp.put(array[i], array[i+1]);
0N/A }
0N/A table = tmp;
0N/A }
0N/A
0N/A /*
0N/A * Shrinks the storage from a hashtable to an array.
0N/A */
0N/A private void shrink() {
0N/A Hashtable tmp = (Hashtable)table;
0N/A Object[] array = new Object[tmp.size()*2];
0N/A Enumeration keys = tmp.keys();
0N/A int j = 0;
0N/A
0N/A while (keys.hasMoreElements()) {
0N/A Object o = keys.nextElement();
0N/A array[j] = o;
0N/A array[j+1] = tmp.get(o);
0N/A j+=2;
0N/A }
0N/A table = array;
0N/A }
0N/A}