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