diff options
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility')
111 files changed, 5573 insertions, 2072 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ClassTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ClassTools.java index 409dd1db3c..c2b7c55f88 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ClassTools.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ClassTools.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -42,11 +42,13 @@ public final class ClassTools { public static final char NESTED_CLASS_NAME_SEPARATOR = '$'; public static final char ARRAY_INDICATOR = '['; + public static final char TYPE_DECLARATION_ARRAY_OPEN = '['; + public static final char TYPE_DECLARATION_ARRAY_CLOSE = ']'; public static final char REFERENCE_CLASS_CODE = 'L'; public static final char REFERENCE_CLASS_NAME_DELIMITER = ';'; - private static PrimitiveClassCode[] PRIMITIVE_CLASS_CODES; // pseudo 'final' - lazy-initialized + private static Primitive[] PRIMITIVES; // pseudo-'final' - lazy-initialized public static final char BYTE_CODE = 'B'; public static final char CHAR_CODE = 'C'; public static final char DOUBLE_CODE = 'D'; @@ -56,8 +58,11 @@ public final class ClassTools { public static final char SHORT_CODE = 'S'; public static final char BOOLEAN_CODE = 'Z'; public static final char VOID_CODE = 'V'; - - private static int MAX_PRIMITIVE_CLASS_NAME_LENGTH = -1; // pseudo 'final' - lazy-initialized + private static int MAX_PRIMITIVE_CLASS_NAME_LENGTH = -1; // pseudo-'final' - lazy-initialized + private static int MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH = -1; // pseudo-'final' - lazy-initialized + + public static final String VOID_CLASS_NAME = void.class.getName(); + public static final String VOID_WRAPPER_CLASS_NAME = java.lang.Void.class.getName(); /** @@ -391,14 +396,14 @@ public final class ClassTools { return field(object.getClass(), fieldName); } - /** + /* * Return a string representation of the specified constructor. */ private static String fullyQualifiedConstructorSignature(Class<?> javaClass, Class<?>[] parameterTypes) { return fullyQualifiedMethodSignature(javaClass, null, parameterTypes); } - /** + /* * Return a string representation of the specified field. */ private static String fullyQualifiedFieldName(Class<?> javaClass, String fieldName) { @@ -409,14 +414,14 @@ public final class ClassTools { return sb.toString(); } - /** + /* * Return a string representation of the specified field. */ private static String fullyQualifiedFieldName(Object object, String fieldName) { return fullyQualifiedFieldName(object.getClass(), fieldName); } - /** + /* * Return a string representation of the specified method. */ private static String fullyQualifiedMethodSignature(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) { @@ -441,7 +446,7 @@ public final class ClassTools { return sb.toString(); } - /** + /* * Return a string representation of the specified method. */ private static String fullyQualifiedMethodSignature(Object receiver, String methodName, Class<?>[] parameterTypes) { @@ -454,7 +459,7 @@ public final class ClassTools { * Useful for accessing private, package, or protected fields. * Object#getFieldValue(String fieldName) */ - public static Object getFieldValue(Object object, String fieldName) { + public static Object fieldValue(Object object, String fieldName) { try { return attemptToGetFieldValue(object, fieldName); } catch (NoSuchFieldException nsfe) { @@ -468,7 +473,7 @@ public final class ClassTools { * Useful for accessing private, package, or protected fields. * Class#getStaticFieldValue(String fieldName) */ - public static Object getStaticFieldValue(Class<?> javaClass, String fieldName) { + public static Object staticFieldValue(Class<?> javaClass, String fieldName) { try { return attemptToGetStaticFieldValue(javaClass, fieldName); } catch (NoSuchFieldException nsfe) { @@ -830,7 +835,7 @@ public final class ClassTools { return newInstance(Class.forName(className, false, classLoader), parameterType, parameter); } - /** + /* * Push the declared fields for the specified class * onto the top of the stack. */ @@ -841,7 +846,7 @@ public final class ClassTools { } } - /** + /* * Push the declared methods for the specified class * onto the top of the stack. */ @@ -1263,21 +1268,25 @@ public final class ClassTools { /** * Return whether the specified class is a "reference" - * class (i.e. not void or one of the primitives). + * class (i.e. neither 'void' nor one of the primitive variable classes, + * ['boolean', 'int', 'float', etc.]). + * NB: void.class.isPrimitive() == true */ public static boolean classNamedIsReference(String className) { - return ! classNamedIsNonReference(className); + return ! classNamedIsPrimitive(className); } /** - * Return whether the specified class is a "non-reference" - * class (i.e. void or one of the primitives). + * Return whether the specified class is a primitive + * class (i.e. 'void' or one of the primitive variable classes, + * ['boolean', 'int', 'float', etc.]). + * NB: void.class.isPrimitive() == true */ - public static boolean classNamedIsNonReference(String className) { + public static boolean classNamedIsPrimitive(String className) { if (classNamedIsArray(className) || (className.length() > maxPrimitiveClassNameLength())) { return false; // performance tweak } - PrimitiveClassCode[] codes = primitiveClassCodes(); + Primitive[] codes = primitives(); for (int i = codes.length; i-- > 0; ) { if (codes[i].javaClass.getName().equals(className)) { return true; @@ -1287,6 +1296,74 @@ public final class ClassTools { } /** + * Return whether the specified class is a "variable" primitive + * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). + * NB: void.class.isPrimitive() == true + */ + public static boolean classNamedIsVariablePrimitive(String className) { + return classNamedIsPrimitive(className) + && ( ! className.equals(VOID_CLASS_NAME)); + } + + /** + * Return whether the specified class is a primitive wrapper + * class (i.e. 'java.lang.Void' or one of the primitive variable wrapper classes, + * ['java.lang.Boolean', 'java.lang.Integer', 'java.lang.Float', etc.]). + * NB: void.class.isPrimitive() == true + */ + public static boolean classNamedIsPrimitiveWrapperClass(String className) { + if (classNamedIsArray(className) || (className.length() > maxPrimitiveWrapperClassNameLength())) { + return false; // performance tweak + } + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].wrapperClass.getName().equals(className)) { + return true; + } + } + return false; + } + + /** + * Return whether the specified class is a "variable" primitive + * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). + * NB: void.class.isPrimitive() == true + */ + public static boolean classNamedIsVariablePrimitiveWrapperClass(String className) { + return classNamedIsPrimitiveWrapperClass(className) + && ( ! className.equals(VOID_WRAPPER_CLASS_NAME)); + } + + /** + * Return whether the specified class is a primitive wrapper + * class (i.e. 'java.lang.Void' or one of the primitive variable wrapper classes, + * ['java.lang.Boolean', 'java.lang.Integer', 'java.lang.Float', etc.]). + * NB: void.class.isPrimitive() == true + */ + public static boolean classIsPrimitiveWrapperClass(Class<?> javaClass) { + if (javaClass.isArray() || (javaClass.getName().length() > maxPrimitiveWrapperClassNameLength())) { + return false; // performance tweak + } + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].wrapperClass == javaClass) { + return true; + } + } + return false; + } + + /** + * Return whether the specified class is a "variable" primitive + * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). + * NB: void.class.isPrimitive() == true + */ + public static boolean classIsVariablePrimitiveWrapperClass(Class<?> javaClass) { + return classIsPrimitiveWrapperClass(javaClass) + && (javaClass != java.lang.Void.class); + } + + /** * Return the class name for the specified class code. * @see java.lang.Class#getName() */ @@ -1307,7 +1384,7 @@ public final class ClassTools { * @see java.lang.Class#getName() */ public static Class<?> classForCode(char classCode) { - PrimitiveClassCode[] codes = primitiveClassCodes(); + Primitive[] codes = primitives(); for (int i = codes.length; i-- > 0; ) { if (codes[i].code == classCode) { return codes[i].javaClass; @@ -1330,7 +1407,7 @@ public final class ClassTools { */ public static char codeForClass(Class<?> javaClass) { if (( ! javaClass.isArray()) && (javaClass.getName().length() <= maxPrimitiveClassNameLength())) { - PrimitiveClassCode[] codes = primitiveClassCodes(); + Primitive[] codes = primitives(); for (int i = codes.length; i-- > 0; ) { if (codes[i].javaClass == javaClass) { return codes[i].code; @@ -1346,7 +1423,7 @@ public final class ClassTools { */ public static char codeForClassNamed(String className) { if (( ! classNamedIsArray(className)) && (className.length() <= maxPrimitiveClassNameLength())) { - PrimitiveClassCode[] codes = primitiveClassCodes(); + Primitive[] codes = primitives(); for (int i = codes.length; i-- > 0; ) { if (codes[i].javaClass.getName().equals(className)) { return codes[i].code; @@ -1357,23 +1434,46 @@ public final class ClassTools { } /** - * Return the class for specified "type declaration". + * Return the class for the specified "type declaration". + */ + public static Class<?> classForTypeDeclaration(String typeDeclaration) throws ClassNotFoundException { + return classForTypeDeclaration(typeDeclaration, ClassTools.class.getClassLoader()); + } + + /** + * Return the class for the specified "type declaration", + * using the specified class loader. + */ + public static Class<?> classForTypeDeclaration(String typeDeclaration, ClassLoader classLoader) throws ClassNotFoundException { + TypeDeclaration td = typeDeclaration(typeDeclaration); + return classForTypeDeclaration(td.elementTypeName, td.arrayDepth); + } + + private static TypeDeclaration typeDeclaration(String typeDeclaration) { + typeDeclaration = StringTools.removeAllWhitespace(typeDeclaration); + int arrayDepth = arrayDepthForTypeDeclaration_(typeDeclaration); + String elementTypeName = typeDeclaration.substring(0, typeDeclaration.length() - (arrayDepth * 2)); + return new TypeDeclaration(elementTypeName, arrayDepth); + } + + /** + * Return the class for the specified "type declaration". */ public static Class<?> classForTypeDeclaration(String elementTypeName, int arrayDepth) throws ClassNotFoundException { return classForTypeDeclaration(elementTypeName, arrayDepth, null); } /** - * Return the class for specified "type declaration", + * Return the class for the specified "type declaration", * using the specified class loader. */ // see the "Evaluation" of jdk bug 6446627 for a discussion of loading classes public static Class<?> classForTypeDeclaration(String elementTypeName, int arrayDepth, ClassLoader classLoader) throws ClassNotFoundException { // primitives cannot be loaded via Class#forName(), // so check for a primitive class name first - PrimitiveClassCode pcc = null; + Primitive pcc = null; if (elementTypeName.length() <= maxPrimitiveClassNameLength()) { // performance tweak - PrimitiveClassCode[] codes = primitiveClassCodes(); + Primitive[] codes = primitives(); for (int i = codes.length; i-- > 0; ) { if (codes[i].javaClass.getName().equals(elementTypeName)) { pcc = codes[i]; @@ -1403,7 +1503,44 @@ public final class ClassTools { } /** - * Return the class name for specified "type declaration". + * Return the class name for the specified "type declaration"; e.g. + * "int[]" -> "[I" + * @see java.lang.Class#getName() + */ + public static String classNameForTypeDeclaration(String typeDeclaration) { + TypeDeclaration td = typeDeclaration(typeDeclaration); + return classNameForTypeDeclaration(td.elementTypeName, td.arrayDepth); + } + + /** + * Return the array depth for the specified "type declaration"; e.g. + * "int[]" -> 1 + */ + public static int arrayDepthForTypeDeclaration(String typeDeclaration) { + return arrayDepthForTypeDeclaration_(StringTools.removeAllWhitespace(typeDeclaration)); + } + + /* + * Assume no whitespace in the type declaration. + */ + private static int arrayDepthForTypeDeclaration_(String typeDeclaration) { + int last = typeDeclaration.length() - 1; + int depth = 0; + int close = last; + while (typeDeclaration.charAt(close) == TYPE_DECLARATION_ARRAY_CLOSE) { + if (typeDeclaration.charAt(close - 1) == TYPE_DECLARATION_ARRAY_OPEN) { + depth++; + } else { + throw new IllegalArgumentException("invalid type declaration: " + typeDeclaration); + } + close = last - (depth * 2); + } + return depth; + } + + /** + * Return the class name for the specified "type declaration". + * @see java.lang.Class#getName() */ public static String classNameForTypeDeclaration(String elementTypeName, int arrayDepth) { // non-array @@ -1411,8 +1548,8 @@ public final class ClassTools { return elementTypeName; } - if (elementTypeName.equals(void.class.getName())) { - throw new IllegalArgumentException("'void' must have an array depth of zero: " + arrayDepth + '.'); + if (elementTypeName.equals(VOID_CLASS_NAME)) { + throw new IllegalArgumentException("'" + VOID_CLASS_NAME + "' must have an array depth of zero: " + arrayDepth + '.'); } // array StringBuilder sb = new StringBuilder(100); @@ -1421,9 +1558,9 @@ public final class ClassTools { } // look for a primitive first - PrimitiveClassCode pcc = null; + Primitive pcc = null; if (elementTypeName.length() <= maxPrimitiveClassNameLength()) { // performance tweak - PrimitiveClassCode[] codes = primitiveClassCodes(); + Primitive[] codes = primitives(); for (int i = codes.length; i-- > 0; ) { if (codes[i].javaClass.getName().equals(elementTypeName)) { pcc = codes[i]; @@ -1452,7 +1589,7 @@ public final class ClassTools { private static int calculateMaxPrimitiveClassNameLength() { int max = -1; - PrimitiveClassCode[] codes = primitiveClassCodes(); + Primitive[] codes = primitives(); for (int i = codes.length; i-- > 0; ) { int len = codes[i].javaClass.getName().length(); if (len > max) { @@ -1462,24 +1599,46 @@ public final class ClassTools { return max; } - private static PrimitiveClassCode[] primitiveClassCodes() { - if (PRIMITIVE_CLASS_CODES == null) { - PRIMITIVE_CLASS_CODES = buildPrimitiveClassCodes(); - } - return PRIMITIVE_CLASS_CODES; - } - - private static PrimitiveClassCode[] buildPrimitiveClassCodes() { - PrimitiveClassCode[] result = new PrimitiveClassCode[9]; - result[0] = new PrimitiveClassCode(BYTE_CODE, byte.class); - result[1] = new PrimitiveClassCode(CHAR_CODE, char.class); - result[2] = new PrimitiveClassCode(DOUBLE_CODE, double.class); - result[3] = new PrimitiveClassCode(FLOAT_CODE, float.class); - result[4] = new PrimitiveClassCode(INT_CODE, int.class); - result[5] = new PrimitiveClassCode(LONG_CODE, long.class); - result[6] = new PrimitiveClassCode(SHORT_CODE, short.class); - result[7] = new PrimitiveClassCode(BOOLEAN_CODE, boolean.class); - result[8] = new PrimitiveClassCode(VOID_CODE, void.class); + private static int maxPrimitiveWrapperClassNameLength() { + if (MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH == -1) { + MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH = calculateMaxPrimitiveWrapperClassNameLength(); + } + return MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH; + } + + private static int calculateMaxPrimitiveWrapperClassNameLength() { + int max = -1; + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + int len = codes[i].wrapperClass.getName().length(); + if (len > max) { + max = len; + } + } + return max; + } + + private static Primitive[] primitives() { + if (PRIMITIVES == null) { + PRIMITIVES = buildPrimitives(); + } + return PRIMITIVES; + } + + /** + * NB: void.class.isPrimitive() == true + */ + private static Primitive[] buildPrimitives() { + Primitive[] result = new Primitive[9]; + result[0] = new Primitive(BYTE_CODE, java.lang.Byte.class); + result[1] = new Primitive(CHAR_CODE, java.lang.Character.class); + result[2] = new Primitive(DOUBLE_CODE, java.lang.Double.class); + result[3] = new Primitive(FLOAT_CODE, java.lang.Float.class); + result[4] = new Primitive(INT_CODE, java.lang.Integer.class); + result[5] = new Primitive(LONG_CODE, java.lang.Long.class); + result[6] = new Primitive(SHORT_CODE, java.lang.Short.class); + result[7] = new Primitive(BOOLEAN_CODE, java.lang.Boolean.class); + result[8] = new Primitive(VOID_CODE, java.lang.Void.class); return result; } @@ -1492,14 +1651,27 @@ public final class ClassTools { } - // ********** member class ********** + // ********** member classes ********** - private static class PrimitiveClassCode { - char code; - Class<?> javaClass; - PrimitiveClassCode(char code, Class<?> javaClass) { + private static class Primitive { + final char code; + final Class<?> javaClass; + final Class<?> wrapperClass; + private static final String WRAPPER_CLASS_TYPE_FIELD_NAME = "TYPE"; + // e.g. java.lang.Boolean.TYPE => boolean.class + Primitive(char code, Class<?> wrapperClass) { this.code = code; - this.javaClass = javaClass; + this.wrapperClass = wrapperClass; + this.javaClass = (Class<?>) staticFieldValue(wrapperClass, WRAPPER_CLASS_TYPE_FIELD_NAME); + } + } + + private static class TypeDeclaration { + final String elementTypeName; + final int arrayDepth; + TypeDeclaration(String elementTypeName, int arrayDepth) { + this.elementTypeName = elementTypeName; + this.arrayDepth = arrayDepth; } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Classpath.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Classpath.java index ff6885e08f..8abad57ec2 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Classpath.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Classpath.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -446,7 +446,7 @@ public class Classpath private static Entry[] consolidateEntries(Classpath[] classpaths) { List<Entry> entries = new ArrayList<Entry>(); for (Classpath classpath : classpaths) { - CollectionTools.addAll(entries, classpath.getEntries()); + CollectionTools.addAll(entries, classpath.entries()); } return entries.toArray(new Entry[entries.size()]); } @@ -457,7 +457,7 @@ public class Classpath /** * Return the classpath's entries. */ - public Entry[] getEntries() { + public Entry[] entries() { return this.entries; } @@ -777,10 +777,10 @@ public class Classpath * under the entry's directory. */ private Iterator<File> classFilesForDirectory() { - return new FilteringIterator<File>(FileTools.filesInTree(this.canonicalFile)) { + return new FilteringIterator<File, File>(FileTools.filesInTree(this.canonicalFile)) { @Override - protected boolean accept(Object next) { - return Entry.this.fileNameMightBeForClassFile(((File) next).getName()); + protected boolean accept(File next) { + return Entry.this.fileNameMightBeForClassFile(next.getName()); } }; } @@ -857,7 +857,7 @@ public class Classpath * the specified filter. */ private Iterator<String> classNamesForDirectory(Filter<String> filter) { - return new FilteringIterator<String>(this.classNamesForDirectory(), filter); + return new FilteringIterator<String, String>(this.classNamesForDirectory(), filter); } /** diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CollectionTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CollectionTools.java index 06e2dcc3fe..2843333b89 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CollectionTools.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CollectionTools.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -31,6 +31,11 @@ import org.eclipse.jpt.utility.internal.iterators.SingleElementIterator; public final class CollectionTools { + @SuppressWarnings("unchecked") + private static <E> E[] newArray(E[] array, int length) { + return (E[]) Array.newInstance(array.getClass().getComponentType(), length); + } + /** * Return a new array that contains the elements in the * specified array followed by the specified object to be added. @@ -38,8 +43,7 @@ public final class CollectionTools { */ public static <E> E[] add(E[] array, E value) { int len = array.length; - @SuppressWarnings("unchecked") - E[] result = (E[]) Array.newInstance(array.getClass().getComponentType(), len + 1); + E[] result = newArray(array, len + 1); System.arraycopy(array, 0, result, 0, len); result[len] = value; return result; @@ -52,8 +56,7 @@ public final class CollectionTools { */ public static <E> E[] add(E[] array, int index, E value) { int len = array.length; - @SuppressWarnings("unchecked") - E[] result = (E[]) Array.newInstance(array.getClass().getComponentType(), len + 1); + E[] result = newArray(array, len + 1); if (index > 0) { System.arraycopy(array, 0, result, 0, index); } @@ -163,9 +166,23 @@ public final class CollectionTools { * java.util.Arrays#addAll(Object[] array, java.util.Collection c) */ public static <E> E[] addAll(E[] array, Collection<? extends E> collection) { + int size = collection.size(); + return (size == 0) ? array : addAll(array, collection, size); + } + + /** + * no parm-checking + */ + private static <E> E[] addAll_(E[] array, Collection<? extends E> collection) { + return addAll(array, collection, collection.size()); + } + + /** + * no parm-checking + */ + private static <E> E[] addAll(E[] array, Collection<? extends E> collection, int collectionSize) { int len = array.length; - @SuppressWarnings("unchecked") - E[] result = (E[]) Array.newInstance(array.getClass().getComponentType(), array.length + collection.size()); + E[] result = newArray(array, array.length + collectionSize); System.arraycopy(array, 0, result, 0, len); int i = len; for (E item : collection) { @@ -191,7 +208,7 @@ public final class CollectionTools { * java.util.Arrays#addAll(Object[] array, java.util.Iterator iterator) */ public static <E> E[] addAll(E[] array, Iterator<? extends E> iterator) { - return addAll(array, list(iterator)); + return (iterator.hasNext()) ? addAll_(array, list(iterator)) : array; } /** @@ -201,12 +218,24 @@ public final class CollectionTools { * java.util.Arrays#addAll(Object[] array1, Object[] array2) */ public static <E> E[] addAll(E[] array1, E[] array2) { - int len1 = array1.length; - int len2 = array2.length; - @SuppressWarnings("unchecked") - E[] result = (E[]) Array.newInstance(array1.getClass().getComponentType(), len1 + len2); - System.arraycopy(array1, 0, result, 0, len1); - System.arraycopy(array2, 0, result, len1, len2); + int array2Length = array2.length; + return (array2Length == 0) ? array1 : addAll(array1, array2, array2Length); + } + + /** + * no parm-checking + */ + private static <E> E[] addAll(E[] array1, E[] array2, int array2Length) { + return addAll(array1, array2, array1.length, array2Length); + } + + /** + * no parm-checking + */ + private static <E> E[] addAll(E[] array1, E[] array2, int array1Length, int array2Length) { + E[] result = newArray(array1, array1Length + array2Length); + System.arraycopy(array1, 0, result, 0, array1Length); + System.arraycopy(array2, 0, result, array1Length, array2Length); return result; } @@ -217,13 +246,29 @@ public final class CollectionTools { * java.util.Arrays#add(Object[] array1, int index, Object[] array2) */ public static <E> E[] addAll(E[] array1, int index, E[] array2) { - int len1 = array1.length; - int len2 = array2.length; - @SuppressWarnings("unchecked") - E[] result = (E[]) Array.newInstance(array1.getClass().getComponentType(), len1 + len2); + int array2Length = array2.length; + return (array2Length == 0) ? array1 : addAll(array1, index, array2, array2Length); + } + + /** + * no array2 length-checking + */ + private static <E> E[] addAll(E[] array1, int index, E[] array2, int array2Length) { + int array1Length = array1.length; + return (index == array1Length) ? + addAll(array1, array2, array1Length, array2Length) + : + addAll(array1, index, array2, array1Length, array2Length); + } + + /** + * no parm-checking + */ + private static <E> E[] addAll(E[] array1, int index, E[] array2, int array1Length, int array2Length) { + E[] result = newArray(array1, array1Length + array2Length); System.arraycopy(array1, 0, result, 0, index); - System.arraycopy(array2, 0, result, index, len2); - System.arraycopy(array1, index, result, index + len2, len1 - index); + System.arraycopy(array2, 0, result, index, array2Length); + System.arraycopy(array1, index, result, index + array2Length, array1Length - index); return result; } @@ -234,11 +279,24 @@ public final class CollectionTools { * java.util.Arrays#addAll(char[] array1, char[] array2) */ public static char[] addAll(char[] array1, char[] array2) { - int len1 = array1.length; - int len2 = array2.length; - char[] result = new char[len1 + len2]; - System.arraycopy(array1, 0, result, 0, len1); - System.arraycopy(array2, 0, result, len1, len2); + int array2Length = array2.length; + return (array2Length == 0) ? array1 : addAll(array1, array2, array2Length); + } + + /** + * no parm-checking + */ + private static char[] addAll(char[] array1, char[] array2, int array2Length) { + return addAll(array1, array2, array1.length, array2Length); + } + + /** + * no parm-checking + */ + private static char[] addAll(char[] array1, char[] array2, int array1Length, int array2Length) { + char[] result = new char[array1Length + array2Length]; + System.arraycopy(array1, 0, result, 0, array1Length); + System.arraycopy(array2, 0, result, array1Length, array2Length); return result; } @@ -249,12 +307,29 @@ public final class CollectionTools { * java.util.Arrays#add(char[] array1, int index, char[] array2) */ public static char[] addAll(char[] array1, int index, char[] array2) { - int len1 = array1.length; - int len2 = array2.length; - char[] result = new char[len1 + len2]; + int array2Length = array2.length; + return (array2Length == 0) ? array1 : addAll(array1, index, array2, array2Length); + } + + /** + * no array2 length-checking + */ + private static char[] addAll(char[] array1, int index, char[] array2, int array2Length) { + int array1Length = array1.length; + return (index == array1Length) ? + addAll(array1, array2, array1Length, array2Length) + : + addAll(array1, index, array2, array1Length, array2Length); + } + + /** + * no parm-checking + */ + private static char[] addAll(char[] array1, int index, char[] array2, int array1Length, int array2Length) { + char[] result = new char[array1Length + array2Length]; System.arraycopy(array1, 0, result, 0, index); - System.arraycopy(array2, 0, result, index, len2); - System.arraycopy(array1, index, result, index + len2, len1 - index); + System.arraycopy(array2, 0, result, index, array2Length); + System.arraycopy(array1, index, result, index + array2Length, array1Length - index); return result; } @@ -265,11 +340,24 @@ public final class CollectionTools { * java.util.Arrays#addAll(int[] array1, int[] array2) */ public static int[] addAll(int[] array1, int[] array2) { - int len1 = array1.length; - int len2 = array2.length; - int[] result = new int[len1 + len2]; - System.arraycopy(array1, 0, result, 0, len1); - System.arraycopy(array2, 0, result, len1, len2); + int array2Length = array2.length; + return (array2Length == 0) ? array1 : addAll(array1, array2, array2Length); + } + + /** + * no parm-checking + */ + private static int[] addAll(int[] array1, int[] array2, int array2Length) { + return addAll(array1, array2, array1.length, array2Length); + } + + /** + * no parm-checking + */ + private static int[] addAll(int[] array1, int[] array2, int array1Length, int array2Length) { + int[] result = new int[array1Length + array2Length]; + System.arraycopy(array1, 0, result, 0, array1Length); + System.arraycopy(array2, 0, result, array1Length, array2Length); return result; } @@ -280,12 +368,29 @@ public final class CollectionTools { * java.util.Arrays#add(int[] array1, int index, int[] array2) */ public static int[] addAll(int[] array1, int index, int[] array2) { - int len1 = array1.length; - int len2 = array2.length; - int[] result = new int[len1 + len2]; + int array2Length = array2.length; + return (array2Length == 0) ? array1 : addAll(array1, index, array2, array2Length); + } + + /** + * no array2 length-checking + */ + private static int[] addAll(int[] array1, int index, int[] array2, int array2Length) { + int array1Length = array1.length; + return (index == array1Length) ? + addAll(array1, array2, array1Length, array2Length) + : + addAll(array1, index, array2, array1Length, array2Length); + } + + /** + * no parm-checking + */ + private static int[] addAll(int[] array1, int index, int[] array2, int array1Length, int array2Length) { + int[] result = new int[array1Length + array2Length]; System.arraycopy(array1, 0, result, 0, index); - System.arraycopy(array2, 0, result, index, len2); - System.arraycopy(array1, index, result, index + len2, len1 - index); + System.arraycopy(array2, 0, result, index, array2Length); + System.arraycopy(array1, index, result, index + array2Length, array1Length - index); return result; } @@ -339,8 +444,9 @@ public final class CollectionTools { * java.util.Iterator#toArray() */ public static Object[] array(Iterator<?> iterator) { - return list(iterator).toArray(); + return (iterator.hasNext()) ? list(iterator).toArray() : EMPTY_OBJECT_ARRAY; } + private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; /** * Return an array corresponding to the specified iterator. @@ -348,7 +454,7 @@ public final class CollectionTools { * java.util.Iterator#toArray() */ public static Object[] array(Iterator<?> iterator, int size) { - return list(iterator, size).toArray(); + return (iterator.hasNext()) ? list(iterator, size).toArray() : EMPTY_OBJECT_ARRAY; } /** @@ -361,7 +467,7 @@ public final class CollectionTools { * java.util.Iterator#toArray(Object[]) */ public static <E> E[] array(Iterator<? extends E> iterator, E[] array) { - return list(iterator).toArray(array); + return (iterator.hasNext()) ? list(iterator).toArray(array) : newArray(array, 0); } /** @@ -374,7 +480,7 @@ public final class CollectionTools { * java.util.Iterator#toArray(Object[]) */ public static <E> E[] array(Iterator<? extends E> iterator, int size, E[] array) { - return list(iterator, size).toArray(array); + return (iterator.hasNext()) ? list(iterator, size).toArray(array) : newArray(array, 0); } /** @@ -1230,17 +1336,40 @@ public final class CollectionTools { * a "for" loop. */ public static <E> Iterable<E> iterable(final Iterator<E> iterator) { - return new Iterable<E>() { - private boolean used = false; - - public Iterator<E> iterator() { - if (used) { - throw new IllegalStateException("This method has already been called"); - } - used = true; - return iterator; + return new SingleUseIterable<E>(iterator); + } + + /** + * This is a one-time use iterable that can return a single iterator. + * Once the iterator is returned the iterable is no longer valid. + * As such, this utility should only be used in one-time use situations, + * such as a 'for-each' loop. + */ + public static class SingleUseIterable<E> implements Iterable<E> { + private Iterator<E> iterator; + + public SingleUseIterable(Iterator<E> iterator) { + super(); + if (iterator == null) { + throw new NullPointerException(); } - }; + this.iterator = iterator; + } + + public Iterator<E> iterator() { + if (this.iterator == null) { + throw new IllegalStateException("This method has already been called."); + } + Iterator<E> result = this.iterator; + this.iterator = null; + return result; + } + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.iterator); + } + } /** @@ -1266,7 +1395,7 @@ public final class CollectionTools { * java.util.ListIterator#lastIndexOf(Object o) */ public static int lastIndexOf(ListIterator<?> iterator, Object value) { - return list(iterator).lastIndexOf(value); + return (iterator.hasNext()) ? list(iterator).lastIndexOf(value) : -1; } /** @@ -1478,9 +1607,13 @@ public final class CollectionTools { * java.util.Arrays#move(Object[] array, int targetIndex, int sourceIndex) */ public static <E> E[] move(E[] array, int targetIndex, int sourceIndex) { - if (targetIndex == sourceIndex) { - return array; - } + return (targetIndex == sourceIndex) ? array : move_(array, targetIndex, sourceIndex); + } + + /** + * no parm-checking + */ + private static <E> E[] move_(E[] array, int targetIndex, int sourceIndex) { E temp = array[sourceIndex]; if (targetIndex < sourceIndex) { System.arraycopy(array, targetIndex, array, targetIndex + 1, sourceIndex - targetIndex); @@ -1497,11 +1630,13 @@ public final class CollectionTools { * java.util.Arrays#move(Object[] array, int targetIndex, int sourceIndex, int length) */ public static <E> E[] move(E[] array, int targetIndex, int sourceIndex, int length) { - if (targetIndex == sourceIndex) { + if ((targetIndex == sourceIndex) || (length == 0)) { return array; } - @SuppressWarnings("unchecked") - E[] temp = (E[]) Array.newInstance(array.getClass().getComponentType(), length); + if (length == 1) { + return move_(array, targetIndex, sourceIndex); + } + E[] temp = newArray(array, length); System.arraycopy(array, sourceIndex, temp, 0, length); if (targetIndex < sourceIndex) { System.arraycopy(array, targetIndex, array, targetIndex + length, sourceIndex - targetIndex); @@ -1518,9 +1653,13 @@ public final class CollectionTools { * java.util.Arrays#move(int[] array, int targetIndex, int sourceIndex) */ public static int[] move(int[] array, int targetIndex, int sourceIndex) { - if (targetIndex == sourceIndex) { - return array; - } + return (targetIndex == sourceIndex) ? array : move_(array, targetIndex, sourceIndex); + } + + /** + * no parm-checking + */ + private static int[] move_(int[] array, int targetIndex, int sourceIndex) { int temp = array[sourceIndex]; if (targetIndex < sourceIndex) { System.arraycopy(array, targetIndex, array, targetIndex + 1, sourceIndex - targetIndex); @@ -1537,9 +1676,12 @@ public final class CollectionTools { * java.util.Arrays#move(int[] array, int targetIndex, int sourceIndex, int length) */ public static int[] move(int[] array, int targetIndex, int sourceIndex, int length) { - if (targetIndex == sourceIndex) { + if ((targetIndex == sourceIndex) || (length == 0)) { return array; } + if (length == 1) { + return move_(array, targetIndex, sourceIndex); + } int[] temp = new int[length]; System.arraycopy(array, sourceIndex, temp, 0, length); if (targetIndex < sourceIndex) { @@ -1557,9 +1699,13 @@ public final class CollectionTools { * java.util.Arrays#move(char[] array, int targetIndex, int sourceIndex) */ public static char[] move(char[] array, int targetIndex, int sourceIndex) { - if (targetIndex == sourceIndex) { - return array; - } + return (targetIndex == sourceIndex) ? array : move_(array, targetIndex, sourceIndex); + } + + /** + * no parm-checking + */ + private static char[] move_(char[] array, int targetIndex, int sourceIndex) { char temp = array[sourceIndex]; if (targetIndex < sourceIndex) { System.arraycopy(array, targetIndex, array, targetIndex + 1, sourceIndex - targetIndex); @@ -1576,9 +1722,12 @@ public final class CollectionTools { * java.util.Arrays#move(char[] array, int targetIndex, int sourceIndex, int length) */ public static char[] move(char[] array, int targetIndex, int sourceIndex, int length) { - if (targetIndex == sourceIndex) { + if ((targetIndex == sourceIndex) || (length == 0)) { return array; } + if (length == 1) { + return move_(array, targetIndex, sourceIndex); + } char[] temp = new char[length]; System.arraycopy(array, sourceIndex, temp, 0, length); if (targetIndex < sourceIndex) { @@ -1596,9 +1745,13 @@ public final class CollectionTools { * java.util.List#move(int targetIndex, int sourceIndex) */ public static <E> List<E> move(List<E> list, int targetIndex, int sourceIndex) { - if (targetIndex == sourceIndex) { - return list; - } + return (targetIndex == sourceIndex) ? list : move_(list, targetIndex, sourceIndex); + } + + /** + * no parm-checking + */ + private static <E> List<E> move_(List<E> list, int targetIndex, int sourceIndex) { if (list instanceof RandomAccess) { // move elements, leaving the list in place E temp = list.get(sourceIndex); @@ -1625,9 +1778,12 @@ public final class CollectionTools { * java.util.List#move(int targetIndex, int sourceIndex, int length) */ public static <E> List<E> move(List<E> list, int targetIndex, int sourceIndex, int length) { - if (targetIndex == sourceIndex) { + if ((targetIndex == sourceIndex) || (length == 0)) { return list; } + if (length == 1) { + return move_(list, targetIndex, sourceIndex); + } if (list instanceof RandomAccess) { // move elements, leaving the list in place ArrayList<E> temp = new ArrayList<E>(list.subList(sourceIndex, sourceIndex + length)); @@ -1771,15 +1927,22 @@ public final class CollectionTools { * java.util.Arrays#removeAll(Object[] array, Collection collection) */ public static <E> E[] removeAll(E[] array, Collection<?> collection) { - E[] result = array; - // go backwards since we will be pulling elements - // out of 'result' and it will get shorter as we go - for (int i = array.length; i-- > 0; ) { - E item = array[i]; - if (collection.contains(item)) { - result = removeElementAtIndex(result, i); + if (collection.isEmpty()) { + return array; + } + int arrayLength = array.length; + int[] indices = new int[arrayLength]; + int j = 0; + for (int i = 0; i < arrayLength; i++) { + if ( ! collection.contains(array[i])) { + indices[j++] = i; } } + E[] result = newArray(array, j); + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array[indices[i]]; + } return result; } @@ -1790,7 +1953,7 @@ public final class CollectionTools { */ public static <E> E[] removeAll(E[] array1, Object[] array2) { // convert to a bag to take advantage of hashed look-up - return removeAll(array1, bag(array2)); + return (array2.length == 0) ? array1 : removeAll(array1, bag(array2)); } /** @@ -1799,16 +1962,23 @@ public final class CollectionTools { * java.util.Arrays#removeAll(char[] array1, char[] array2) */ public static char[] removeAll(char[] array1, char[] array2) { - char[] result1 = array1; - // go backwards since we will be pulling elements - // out of 'result1' and it will get shorter as we go - for (int i = array1.length; i-- > 0; ) { - char item = array1[i]; - if (contains(array2, item)) { - result1 = removeElementAtIndex(result1, i); + if (array2.length == 0) { + return array1; + } + int array1Length = array1.length; + int[] indices = new int[array1Length]; + int j = 0; + for (int i = 0; i < array1Length; i++) { + if ( ! contains(array2, array1[i])) { + indices[j++] = i; } } - return result1; + char[] result = new char[j]; + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array1[indices[i]]; + } + return result; } /** @@ -1817,16 +1987,23 @@ public final class CollectionTools { * java.util.Arrays#removeAll(int[] array1, int[] array2) */ public static int[] removeAll(int[] array1, int[] array2) { - int[] result1 = array1; - // go backwards since we will be pulling elements - // out of 'result1' and it will get shorter as we go - for (int i = array1.length; i-- > 0; ) { - int item = array1[i]; - if (contains(array2, item)) { - result1 = removeElementAtIndex(result1, i); + if (array2.length == 0) { + return array1; + } + int array1Length = array1.length; + int[] indices = new int[array1Length]; + int j = 0; + for (int i = 0; i < array1Length; i++) { + if ( ! contains(array2, array1[i])) { + indices[j++] = i; } } - return result1; + int[] result = new int[j]; + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array1[indices[i]]; + } + return result; } /** @@ -1862,24 +2039,27 @@ public final class CollectionTools { * java.util.Arrays#removeAllOccurrences(Object[] array, Object value) */ public static <E> E[] removeAllOccurrences(E[] array, Object value) { - E[] result = array; + int arrayLength = array.length; + int[] indices = new int[arrayLength]; + int j = 0; if (value == null) { - // go backwards since we will be pulling elements - // out of 'result' and it will get shorter as we go - for (int i = array.length; i-- > 0; ) { - if (array[i] == null) { - result = removeElementAtIndex(result, i); + for (int i = arrayLength; i-- > 0; ) { + if (array[i] != null) { + indices[j++] = i; } } } else { - // go backwards since we will be pulling elements - // out of 'result' and it will get shorter as we go for (int i = array.length; i-- > 0; ) { - if (value.equals(array[i])) { - result = removeElementAtIndex(result, i); + if ( ! value.equals(array[i])) { + indices[j++] = i; } } } + E[] result = newArray(array, j); + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array[indices[i]]; + } return result; } @@ -1889,14 +2069,19 @@ public final class CollectionTools { * java.util.Arrays#removeAllOccurrences(char[] array, char value) */ public static char[] removeAllOccurrences(char[] array, char value) { - char[] result = array; - // go backwards since we will be pulling elements - // out of 'result' and it will get shorter as we go - for (int i = array.length; i-- > 0; ) { - if (array[i] == value) { - result = removeElementAtIndex(result, i); + int arrayLength = array.length; + int[] indices = new int[arrayLength]; + int j = 0; + for (int i = arrayLength; i-- > 0; ) { + if (array[i] != value) { + indices[j++] = i; } } + char[] result = new char[j]; + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array[indices[i]]; + } return result; } @@ -1906,14 +2091,19 @@ public final class CollectionTools { * java.util.Arrays#removeAllOccurrences(int[] array, int value) */ public static int[] removeAllOccurrences(int[] array, int value) { - int[] result = array; - // go backwards since we will be pulling elements - // out of 'result' and it will get shorter as we go - for (int i = array.length; i-- > 0; ) { - if (array[i] == value) { - result = removeElementAtIndex(result, i); + int arrayLength = array.length; + int[] indices = new int[arrayLength]; + int j = 0; + for (int i = arrayLength; i-- > 0; ) { + if (array[i] != value) { + indices[j++] = i; } } + int[] result = new int[j]; + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array[indices[i]]; + } return result; } @@ -1963,11 +2153,14 @@ public final class CollectionTools { * java.util.Arrays#removeElementsAtIndex(Object[] array, int index, int length) */ public static <E> E[] removeElementsAtIndex(E[] array, int index, int length) { - int len = array.length; - @SuppressWarnings("unchecked") - E[] result = (E[]) Array.newInstance(array.getClass().getComponentType(), len - length); + int arrayLength = array.length; + int newLength = arrayLength - length; + E[] result = newArray(array, newLength); + if ((newLength == 0) && (index == 0)) { + return result; // performance tweak + } System.arraycopy(array, 0, result, 0, index); - System.arraycopy(array, index + length, result, index, len - index - length); + System.arraycopy(array, index + length, result, index, newLength - index); return result; } @@ -1977,12 +2170,17 @@ public final class CollectionTools { * java.util.Arrays#removeElementAtIndex(char[] array, int index, int length) */ public static char[] removeElementsAtIndex(char[] array, int index, int length) { - int len = array.length; - char[] result = new char[len - length]; + int arrayLength = array.length; + int newLength = arrayLength - length; + if ((newLength == 0) && (index == 0)) { + return EMPTY_CHAR_ARRAY; // performance tweak + } + char[] result = new char[newLength]; System.arraycopy(array, 0, result, 0, index); - System.arraycopy(array, index + length, result, index, len - index - length); + System.arraycopy(array, index + length, result, index, newLength - index); return result; } + private static final char[] EMPTY_CHAR_ARRAY = new char[0]; /** * Return a new array that contains the elements in the @@ -1990,22 +2188,29 @@ public final class CollectionTools { * java.util.Arrays#removeElementAtIndex(int[] array, int index, int length) */ public static int[] removeElementsAtIndex(int[] array, int index, int length) { - int len = array.length; - int[] result = new int[len - length]; + int arrayLength = array.length; + int newLength = arrayLength - length; + if ((newLength == 0) && (index == 0)) { + return EMPTY_INT_ARRAY; // performance tweak + } + int[] result = new int[newLength]; System.arraycopy(array, 0, result, 0, index); - System.arraycopy(array, index + length, result, index, len - index - length); + System.arraycopy(array, index + length, result, index, newLength - index); return result; } + private static final int[] EMPTY_INT_ARRAY = new int[0]; /** * Remove any duplicate elements from the specified array, * while maintaining the order. */ public static <E> E[] removeDuplicateElements(E... array) { - List<E> list = removeDuplicateElements(Arrays.asList(array)); - @SuppressWarnings("unchecked") - E[] resultArray = (E[]) Array.newInstance(array.getClass().getComponentType(), list.size()); - return list.toArray(resultArray); + int len = array.length; + if ((len == 0) || (len == 1)) { + return array; + } + List<E> list = removeDuplicateElements(Arrays.asList(array), len); + return list.toArray(newArray(array, list.size())); } /** @@ -2013,8 +2218,19 @@ public final class CollectionTools { * while maintaining the order. */ public static <E> List<E> removeDuplicateElements(List<E> list) { - List<E> result = new ArrayList<E>(list.size()); - Set<E> set = new HashSet<E>(list.size()); // take advantage of hashed look-up + int size = list.size(); + if ((size == 0) || (size == 1)) { + return list; + } + return removeDuplicateElements(list, size); + } + + /** + * no parm-checking + */ + private static <E> List<E> removeDuplicateElements(List<E> list, int size) { + List<E> result = new ArrayList<E>(size); + Set<E> set = new HashSet<E>(size); // take advantage of hashed look-up for (E item : list) { if (set.add(item)) { result.add(item); @@ -2040,7 +2256,14 @@ public final class CollectionTools { * java.util.Collection#retainAll(java.util.Iterator iterator) */ public static boolean retainAll(Collection<?> collection, Iterator<?> iterator) { - return collection.retainAll(collection(iterator)); + if (iterator.hasNext()) { + return collection.retainAll(set(iterator)); + } + if (collection.isEmpty()) { + return false; + } + collection.clear(); + return true; } /** @@ -2050,7 +2273,14 @@ public final class CollectionTools { * java.util.Collection#retainAll(Object[] array) */ public static boolean retainAll(Collection<?> collection, Object[] array) { - return collection.retainAll(set(array)); + if (array.length > 0) { + return collection.retainAll(set(array)); + } + if (collection.isEmpty()) { + return false; + } + collection.clear(); + return true; } /** @@ -2059,14 +2289,29 @@ public final class CollectionTools { * java.util.Arrays#retainAll(Object[] array, Collection collection) */ public static <E> E[] retainAll(E[] array, Collection<?> collection) { - E[] result = array; - // go backwards since we will be pulling elements - // out of 'result' and it will get shorter as we go - for (int i = array.length; i-- > 0; ) { - if ( ! collection.contains(array[i])) { - result = removeElementAtIndex(result, i); + int arrayLength = array.length; + return (collection.isEmpty()) ? + (arrayLength == 0) ? array : newArray(array, 0) + : + retainAll(array, collection, arrayLength); + } + + /** + * no parm-checking + */ + private static <E> E[] retainAll(E[] array, Collection<?> collection, int arrayLength) { + int[] indices = new int[arrayLength]; + int j = 0; + for (int i = 0; i < arrayLength; i++) { + if (collection.contains(array[i])) { + indices[j++] = i; } } + E[] result = newArray(array, j); + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array[indices[i]]; + } return result; } @@ -2076,8 +2321,11 @@ public final class CollectionTools { * java.util.Arrays#retainAll(Object[] array1, Object[] array2) */ public static <E> E[] retainAll(E[] array1, Object[] array2) { - // convert to a bag to take advantage of hashed look-up - return retainAll(array1, bag(array2)); + int array1Length = array1.length; + return (array2.length == 0) ? + (array1Length == 0) ? array1 : newArray(array1, 0) + : + retainAll(array1, set(array2), array1Length); } /** @@ -2086,34 +2334,64 @@ public final class CollectionTools { * java.util.Arrays#retainAll(char[] array1, char[] array2) */ public static char[] retainAll(char[] array1, char[] array2) { - char[] result1 = array1; - // go backwards since we will be pulling elements - // out of 'result1' and it will get shorter as we go - for (int i = array1.length; i-- > 0; ) { - char item = array1[i]; - if ( ! contains(array2, item)) { - result1 = removeElementAtIndex(result1, i); + int array1Length = array1.length; + int array2Length = array2.length; + return (array2Length == 0) ? + (array1Length == 0) ? array1 : EMPTY_CHAR_ARRAY + : + retainAll(array1, array2, array1Length, array2Length); + } + + /** + * no parm-checking + */ + private static char[] retainAll(char[] array1, char[] array2, int array1Length, int array2Length) { + int[] indices = new int[array1Length]; + int j = 0; + for (int i = 0; i < array1Length; i++) { + if (contains(array2, array1[i])) { + indices[j++] = i; } } - return result1; + char[] result = new char[j]; + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array1[indices[i]]; + } + return result; } /** * Remove from the first specified array all the elements in * the second specified array and return the result. - * java.util.Arrays#removeAll(int[] array1, int[] array2) + * java.util.Arrays#retainAll(int[] array1, int[] array2) */ public static int[] retainAll(int[] array1, int[] array2) { - int[] result1 = array1; - // go backwards since we will be pulling elements - // out of 'result1' and it will get shorter as we go - for (int i = array1.length; i-- > 0; ) { - int item = array1[i]; - if ( ! contains(array2, item)) { - result1 = removeElementAtIndex(result1, i); + int array1Length = array1.length; + int array2Length = array2.length; + return (array2Length == 0) ? + (array1Length == 0) ? array1 : EMPTY_INT_ARRAY + : + retainAll(array1, array2, array1Length, array2Length); + } + + /** + * no parm-checking + */ + private static int[] retainAll(int[] array1, int[] array2, int array1Length, int array2Length) { + int[] indices = new int[array1Length]; + int j = 0; + for (int i = 0; i < array1Length; i++) { + if (contains(array2, array1[i])) { + indices[j++] = i; } } - return result1; + int[] result = new int[j]; + int resultLength = result.length; + for (int i = 0; i < resultLength; i++) { + result[i] = array1[indices[i]]; + } + return result; } /** @@ -2182,7 +2460,7 @@ public final class CollectionTools { */ public static <E> E[] rotate(E[] array, int distance) { int len = array.length; - if (len == 0) { + if ((len == 0) || (len == 1)) { return array; } distance = distance % len; @@ -2223,7 +2501,7 @@ public final class CollectionTools { */ public static char[] rotate(char[] array, int distance) { int len = array.length; - if (len == 0) { + if ((len == 0) || (len == 1)) { return array; } distance = distance % len; @@ -2264,7 +2542,7 @@ public final class CollectionTools { */ public static int[] rotate(int[] array, int distance) { int len = array.length; - if (len == 0) { + if ((len == 0) || (len == 1)) { return array; } distance = distance % len; @@ -2358,6 +2636,9 @@ public final class CollectionTools { */ public static <E> E[] shuffle(E[] array, Random random) { int len = array.length; + if ((len == 0) || (len == 1)) { + return array; + } for (int i = len; i-- > 0; ) { swap(array, i, random.nextInt(len)); } @@ -2378,6 +2659,9 @@ public final class CollectionTools { */ public static char[] shuffle(char[] array, Random random) { int len = array.length; + if ((len == 0) || (len == 1)) { + return array; + } for (int i = len; i-- > 0; ) { swap(array, i, random.nextInt(len)); } @@ -2398,6 +2682,9 @@ public final class CollectionTools { */ public static int[] shuffle(int[] array, Random random) { int len = array.length; + if ((len == 0) || (len == 1)) { + return array; + } for (int i = len; i-- > 0; ) { swap(array, i, random.nextInt(len)); } @@ -2533,9 +2820,10 @@ public final class CollectionTools { * java.util.Arrays#subArray(E[] array, int start, int length) */ public static <E> E[] subArray(E[] array, int start, int length) { - @SuppressWarnings("unchecked") - E[] result = (E[]) Array.newInstance(array.getClass().getComponentType(), length); - System.arraycopy(array, start, result, 0, length); + E[] result = newArray(array, length); + if (length > 0) { + System.arraycopy(array, start, result, 0, length); + } return result; } @@ -2546,7 +2834,9 @@ public final class CollectionTools { */ public static int[] subArray(int[] array, int start, int length) { int[] result = new int[length]; - System.arraycopy(array, start, result, 0, length); + if (length > 0) { + System.arraycopy(array, start, result, 0, length); + } return result; } @@ -2557,7 +2847,9 @@ public final class CollectionTools { */ public static char[] subArray(char[] array, int start, int length) { char[] result = new char[length]; - System.arraycopy(array, start, result, 0, length); + if (length > 0) { + System.arraycopy(array, start, result, 0, length); + } return result; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/FileTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/FileTools.java index 0374578e70..44154c4ed5 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/FileTools.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/FileTools.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -187,10 +187,10 @@ public final class FileTools { } private static Iterator<File> filesIn(File[] files) { - return new FilteringIterator<File>(new ArrayIterator<File>(files)) { + return new FilteringIterator<File, File>(new ArrayIterator<File>(files)) { @Override - protected boolean accept(Object next) { - return ((File) next).isFile(); + protected boolean accept(File next) { + return next.isFile(); } }; } @@ -214,10 +214,10 @@ public final class FileTools { } private static Iterator<File> directoriesIn(File[] files) { - return new FilteringIterator<File>(new ArrayIterator<File>(files)) { + return new FilteringIterator<File, File>(new ArrayIterator<File>(files)) { @Override - protected boolean accept(Object next) { - return ((File) next).isDirectory(); + protected boolean accept(File next) { + return next.isDirectory(); } }; } @@ -816,10 +816,10 @@ public final class FileTools { * File#files(FileFilter fileFilter) */ public static Iterator<File> filter(Iterator<File> files, final FileFilter fileFilter) { - return new FilteringIterator<File>(files) { + return new FilteringIterator<File, File>(files) { @Override - protected boolean accept(Object next) { - return fileFilter.accept((File) next); + protected boolean accept(File next) { + return fileFilter.accept(next); } }; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IndentingPrintWriter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IndentingPrintWriter.java index c510c86ebb..f2afb1d4e6 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IndentingPrintWriter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IndentingPrintWriter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -132,7 +132,7 @@ public class IndentingPrintWriter extends PrintWriter { /** * Return the current indent level. */ - public int getIndentLevel() { + public int indentLevel() { return this.indentLevel; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCTools.java index 91f307c551..e34316fc3b 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCTools.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCTools.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -57,7 +57,7 @@ public final class JDBCTools { * @see java.sql.Types */ public static JavaType javaTypeFor(JDBCType jdbcType) { - return javaTypeForJDBCTypeNamed(jdbcType.getName()); + return javaTypeForJDBCTypeNamed(jdbcType.name()); } /** @@ -141,9 +141,9 @@ public final class JDBCTools { private static void addJDBCToJavaTypeMappingTo(int jdbcTypeCode, Class<?> javaClass, HashMap<String, JDBCToJavaTypeMapping> mappings) { // check for duplicates JDBCType jdbcType = JDBCType.type(jdbcTypeCode); - Object prev = mappings.put(jdbcType.getName(), buildJDBCToJavaTypeMapping(jdbcType, javaClass)); + Object prev = mappings.put(jdbcType.name(), buildJDBCToJavaTypeMapping(jdbcType, javaClass)); if (prev != null) { - throw new IllegalArgumentException("duplicate JDBC type: " + jdbcType.getName()); + throw new IllegalArgumentException("duplicate JDBC type: " + jdbcType.name()); } } @@ -267,11 +267,11 @@ public final class JDBCTools { } public boolean maps(int jdbcTypeCode) { - return this.jdbcType.getCode() == jdbcTypeCode; + return this.jdbcType.code() == jdbcTypeCode; } public boolean maps(String jdbcTypeName) { - return this.jdbcType.getName().equals(jdbcTypeName); + return this.jdbcType.name().equals(jdbcTypeName); } public boolean maps(JDBCType type) { diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCType.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCType.java index 6af61e270e..82ae294c34 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCType.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCType.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -57,7 +57,7 @@ public final class JDBCType /** * Return the name of the type, as defined in java.sql.Types. */ - public String getName() { + public String name() { return this.name; } @@ -65,7 +65,7 @@ public final class JDBCType /** * Return the type code, as defined in java.sql.Types. */ - public int getCode() { + public int code() { return this.code; } @@ -122,7 +122,7 @@ public final class JDBCType public static JDBCType type(int code) { JDBCType[] types = types(); for (int i = types.length; i-- > 0; ) { - if (types[i].getCode() == code) { + if (types[i].code() == code) { return types[i]; } } @@ -136,7 +136,7 @@ public final class JDBCType public static JDBCType type(String name) { JDBCType[] types = types(); for (int i = types.length; i-- > 0; ) { - if (types[i].getName().equals(name)) { + if (types[i].name().equals(name)) { return types[i]; } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JavaType.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JavaType.java index dffd4f07fb..de075524ee 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JavaType.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JavaType.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -87,14 +87,14 @@ public final class JavaType * Return the name of the type's "element type". * A member type will have one or more '$' characters in its name. */ - public String getElementTypeName() { + public String elementTypeName() { return this.elementTypeName; } /** * Return the type's "array depth". */ - public int getArrayDepth() { + public int arrayDepth() { return this.arrayDepth; } @@ -105,8 +105,32 @@ public final class JavaType return this.arrayDepth > 0; } + /** + * NB: void.class.isPrimitive() == true + */ public boolean isPrimitive() { - return (this.arrayDepth == 0) && ClassTools.classNamedIsNonReference(this.elementTypeName); + return (this.arrayDepth == 0) && ClassTools.classNamedIsPrimitive(this.elementTypeName); + } + + /** + * NB: void.class.isPrimitive() == true + */ + public boolean isPrimitiveWrapper() { + return (this.arrayDepth == 0) && ClassTools.classNamedIsPrimitiveWrapperClass(this.elementTypeName); + } + + /** + * NB: variables cannot be declared 'void' + */ + public boolean isVariablePrimitive() { + return (this.arrayDepth == 0) && ClassTools.classNamedIsVariablePrimitive(this.elementTypeName); + } + + /** + * NB: variables cannot be declared 'void' + */ + public boolean isVariablePrimitiveWrapper() { + return (this.arrayDepth == 0) && ClassTools.classNamedIsVariablePrimitiveWrapperClass(this.elementTypeName); } /** diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NameTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NameTools.java index 264cc073ac..5610f00845 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NameTools.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NameTools.java @@ -122,7 +122,7 @@ public final class NameTools { */ public static String buildQualifiedDatabaseObjectName(String catalog, String schema, String name) { if (name == null) { - throw new IllegalArgumentException(); + return null; } if ((catalog == null) && (schema == null)) { return name; diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ReverseComparator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ReverseComparator.java index 16ff4584d5..10c01f80f0 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ReverseComparator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ReverseComparator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -30,7 +30,6 @@ public class ReverseComparator<E extends Comparable<? super E>> this.comparator = comparator; } - @SuppressWarnings("unchecked") public int compare(E e1, E e2) { return (this.comparator == null) ? e2.compareTo(e1) diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java index e45bea5269..f183943d9a 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -10,6 +10,7 @@ package org.eclipse.jpt.utility.internal; import java.io.Serializable; +import java.util.Collection; import java.util.EmptyStackException; import java.util.LinkedList; import java.util.NoSuchElementException; @@ -35,6 +36,18 @@ public class SimpleStack<E> this.elements = new LinkedList<E>(); } + /** + * Construct a stack containing the elements of the specified + * collection. The stack will pop its elements in reverse of the + * order they are returned by the collection's iterator (i.e. the + * last element returned by the collection's iterator will be the + * first element returned by #pop()). + */ + public SimpleStack(Collection<? extends E> c) { + super(); + this.elements = new LinkedList<E>(c); + } + // ********** Stack implementation ********** diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStringMatcher.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStringMatcher.java index 7de0f24255..6ea439dda6 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStringMatcher.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStringMatcher.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -37,12 +37,12 @@ import java.util.regex.Pattern; * object is compared to the pattern. By default the string returned * by the object's #toString() method is passed to the pattern matcher. */ -public class SimpleStringMatcher - implements StringMatcher, Filter, Serializable +public class SimpleStringMatcher<T> + implements StringMatcher, Filter<T>, Serializable { /** An adapter that converts the objects into strings to be matched with the pattern. */ - private StringConverter stringConverter; + private StringConverter<T> stringConverter; /** The string used to construct the regular expression pattern. */ private String patternString; @@ -135,7 +135,7 @@ public class SimpleStringMatcher // ********** Filter implementation ********** - public synchronized boolean accept(Object o) { + public synchronized boolean accept(T o) { return this.matches(this.stringConverter.convertToString(o)); } @@ -146,7 +146,7 @@ public class SimpleStringMatcher * Return the string converter used to convert the objects * passed to the matcher into strings. */ - public synchronized StringConverter getStringConverter() { + public synchronized StringConverter<T> stringConverter() { return this.stringConverter; } @@ -154,14 +154,14 @@ public class SimpleStringMatcher * Set the string converter used to convert the objects * passed to the matcher into strings. */ - public synchronized void setStringConverter(StringConverter stringConverter) { + public synchronized void setStringConverter(StringConverter<T> stringConverter) { this.stringConverter = stringConverter; } /** * Return the original pattern string. */ - public synchronized String getPatternString() { + public synchronized String patternString() { return this.patternString; } @@ -183,7 +183,7 @@ public class SimpleStringMatcher /** * Return the regular expression pattern. */ - public synchronized Pattern getPattern() { + public synchronized Pattern pattern() { return this.pattern; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringMatcher.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringMatcher.java index 5dd8f28725..5f769d7040 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringMatcher.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringMatcher.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -33,19 +33,26 @@ public interface StringMatcher { boolean matches(String string); - StringMatcher NULL_INSTANCE = - new StringMatcher() { - public void setPatternString(String patternString) { - // ignore the pattern string - } - public boolean matches(String string) { - // everything is a match - return true; - } - @Override - public String toString() { - return "NullStringMatcher"; - } - }; + final class Null implements StringMatcher { + public static final StringMatcher INSTANCE = new Null(); + public static StringMatcher instance() { + return INSTANCE; + } + // ensure single instance + private Null() { + super(); + } + public void setPatternString(String patternString) { + // ignore the pattern string + } + public boolean matches(String string) { + // everything is a match + return true; + } + @Override + public String toString() { + return "StringMatcher.Null"; + } + } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringTools.java index 75d399b443..a7cc25a96c 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringTools.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringTools.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -91,7 +91,7 @@ public final class StringTools { if (stringLength == length) { return string; } - return padInternal(string, length, c); + return pad_(string, length, c); } /** @@ -103,7 +103,15 @@ public final class StringTools { * String#padOn(int, char, Writer) */ public static void padOn(String string, int length, char c, Writer writer) { - padOn(string.toCharArray(), length, c, writer); + int stringLength = string.length(); + if (stringLength > length) { + throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); + } + if (stringLength == length) { + writeStringOn(string, writer); + } else { + padOn_(string, length, c, writer); + } } /** @@ -115,7 +123,15 @@ public final class StringTools { * String#padOn(int, char, StringBuffer) */ public static void padOn(String string, int length, char c, StringBuffer sb) { - padOn(string.toCharArray(), length, c, sb); + int stringLength = string.length(); + if (stringLength > length) { + throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); + } + if (stringLength == length) { + sb.append(string); + } else { + padOn_(string, length, c, sb); + } } /** @@ -127,7 +143,15 @@ public final class StringTools { * String#padOn(int, char, StringBuilder) */ public static void padOn(String string, int length, char c, StringBuilder sb) { - padOn(string.toCharArray(), length, c, sb); + int stringLength = string.length(); + if (stringLength > length) { + throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); + } + if (stringLength == length) { + sb.append(string); + } else { + padOn_(string, length, c, sb); + } } /** @@ -190,7 +214,7 @@ public final class StringTools { if (stringLength == length) { return string; } - return padInternal(string, length, c); + return pad_(string, length, c); } /** @@ -209,7 +233,7 @@ public final class StringTools { if (stringLength == length) { writeStringOn(string, writer); } else { - padOnInternal(string, length, c, writer); + padOn_(string, length, c, writer); } } @@ -229,7 +253,7 @@ public final class StringTools { if (stringLength == length) { sb.append(string); } else { - padOnInternal(string, length, c, sb); + padOn_(string, length, c, sb); } } @@ -249,7 +273,7 @@ public final class StringTools { if (stringLength == length) { sb.append(string); } else { - padOnInternal(string, length, c, sb); + padOn_(string, length, c, sb); } } @@ -313,7 +337,7 @@ public final class StringTools { if (stringLength > length) { return string.substring(0, length); } - return padInternal(string, length, c); + return pad_(string, length, c); } /** @@ -325,7 +349,14 @@ public final class StringTools { * String#padOrTruncateOn(int, char, Writer) */ public static void padOrTruncateOn(String string, int length, char c, Writer writer) { - padOrTruncateOn(string.toCharArray(), length, c, writer); + int stringLength = string.length(); + if (stringLength == length) { + writeStringOn(string, writer); + } else if (stringLength > length) { + writeStringOn(string.substring(0, length), writer); + } else { + padOn_(string, length, c, writer); + } } /** @@ -337,7 +368,14 @@ public final class StringTools { * String#padOrTruncateOn(int, char, StringBuffer) */ public static void padOrTruncateOn(String string, int length, char c, StringBuffer sb) { - padOrTruncateOn(string.toCharArray(), length, c, sb); + int stringLength = string.length(); + if (stringLength == length) { + sb.append(string); + } else if (stringLength > length) { + sb.append(string.substring(0, length)); + } else { + padOn_(string, length, c, sb); + } } /** @@ -349,7 +387,14 @@ public final class StringTools { * String#padOrTruncateOn(int, char, StringBuilder) */ public static void padOrTruncateOn(String string, int length, char c, StringBuilder sb) { - padOrTruncateOn(string.toCharArray(), length, c, sb); + int stringLength = string.length(); + if (stringLength == length) { + sb.append(string); + } else if (stringLength > length) { + sb.append(string.substring(0, length)); + } else { + padOn_(string, length, c, sb); + } } /** @@ -414,7 +459,7 @@ public final class StringTools { System.arraycopy(string, 0, result, 0, length); return result; } - return padInternal(string, length, c); + return pad_(string, length, c); } /** @@ -432,7 +477,7 @@ public final class StringTools { } else if (stringLength > length) { writeStringOn(string, 0, length, writer); } else { - padOnInternal(string, length, c, writer); + padOn_(string, length, c, writer); } } @@ -451,7 +496,7 @@ public final class StringTools { } else if (stringLength > length) { sb.append(string, 0, length); } else { - padOnInternal(string, length, c, sb); + padOn_(string, length, c, sb); } } @@ -470,21 +515,117 @@ public final class StringTools { } else if (stringLength > length) { sb.append(string, 0, length); } else { - padOnInternal(string, length, c, sb); + padOn_(string, length, c, sb); } } - /** + /* * Pad the specified string without validating the parms. */ - private static String padInternal(String string, int length, char c) { - return new String(padInternal(string.toCharArray(), length, c)); + private static String pad_(String string, int length, char c) { + return new String(pad_(string.toCharArray(), length, c)); } - /** + /* * Pad the specified string without validating the parms. */ - private static char[] padInternal(char[] string, int length, char c) { + private static void padOn_(String string, int length, char c, Writer writer) { + writeStringOn(string, writer); + fill_(string, length, c, writer); + } + + /* + * Add enough characters to the specified writer to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(String string, int length, char c, Writer writer) { + fill_(string.length(), length, c, writer); + } + + /* + * Add enough characters to the specified writer to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(char[] string, int length, char c, Writer writer) { + fill_(string.length, length, c, writer); + } + + /* + * Add enough characters to the specified writer to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(int stringLength, int length, char c, Writer writer) { + writeStringOn(CollectionTools.fill(new char[length - stringLength], c), writer); + } + + /* + * Pad the specified string without validating the parms. + */ + private static void padOn_(String string, int length, char c, StringBuffer sb) { + sb.append(string); + fill_(string, length, c, sb); + } + + /* + * Add enough characters to the specified string buffer to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(String string, int length, char c, StringBuffer sb) { + fill_(string.length(), length, c, sb); + } + + /* + * Add enough characters to the specified string buffer to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(char[] string, int length, char c, StringBuffer sb) { + fill_(string.length, length, c, sb); + } + + /* + * Add enough characters to the specified string buffer to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(int stringLength, int length, char c, StringBuffer sb) { + sb.append(CollectionTools.fill(new char[length - stringLength], c)); + } + + /* + * Pad the specified string without validating the parms. + */ + private static void padOn_(String string, int length, char c, StringBuilder sb) { + sb.append(string); + fill_(string, length, c, sb); + } + + /* + * Add enough characters to the specified string builder to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(String string, int length, char c, StringBuilder sb) { + fill_(string.length(), length, c, sb); + } + + /* + * Add enough characters to the specified string builder to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(char[] string, int length, char c, StringBuilder sb) { + fill_(string.length, length, c, sb); + } + + /* + * Add enough characters to the specified string builder to compensate for + * the difference between the specified string and specified length. + */ + private static void fill_(int stringLength, int length, char c, StringBuilder sb) { + sb.append(CollectionTools.fill(new char[length - stringLength], c)); + } + + /* + * Pad the specified string without validating the parms. + */ + private static char[] pad_(char[] string, int length, char c) { char[] result = new char[length]; int stringLength = string.length; System.arraycopy(string, 0, result, 0, stringLength); @@ -492,28 +633,28 @@ public final class StringTools { return result; } - /** + /* * Pad the specified string without validating the parms. */ - private static void padOnInternal(char[] string, int length, char c, Writer writer) { + private static void padOn_(char[] string, int length, char c, Writer writer) { writeStringOn(string, writer); - writeStringOn(CollectionTools.fill(new char[length - string.length], c), writer); + fill_(string, length, c, writer); } - /** + /* * Pad the specified string without validating the parms. */ - private static void padOnInternal(char[] string, int length, char c, StringBuffer sb) { + private static void padOn_(char[] string, int length, char c, StringBuffer sb) { sb.append(string); - sb.append(CollectionTools.fill(new char[length - string.length], c)); + fill_(string, length, c, sb); } - /** + /* * Pad the specified string without validating the parms. */ - private static void padOnInternal(char[] string, int length, char c, StringBuilder sb) { + private static void padOn_(char[] string, int length, char c, StringBuilder sb) { sb.append(string); - sb.append(CollectionTools.fill(new char[length - string.length], c)); + fill_(string, length, c, sb); } /** @@ -576,7 +717,7 @@ public final class StringTools { if (stringLength == length) { return string; } - return frontPadInternal(string, length, c); + return frontPad_(string, length, c); } /** @@ -588,7 +729,15 @@ public final class StringTools { * String#frontPadOn(int, char, Writer) */ public static void frontPadOn(String string, int length, char c, Writer writer) { - frontPadOn(string.toCharArray(), length, c, writer); + int stringLength = string.length(); + if (stringLength > length) { + throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); + } + if (stringLength == length) { + writeStringOn(string, writer); + } else { + frontPadOn_(string, length, c, writer); + } } /** @@ -600,7 +749,15 @@ public final class StringTools { * String#frontPadOn(int, char, StringBuffer) */ public static void frontPadOn(String string, int length, char c, StringBuffer sb) { - frontPadOn(string.toCharArray(), length, c, sb); + int stringLength = string.length(); + if (stringLength > length) { + throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); + } + if (stringLength == length) { + sb.append(string); + } else { + frontPadOn_(string, length, c, sb); + } } /** @@ -612,7 +769,15 @@ public final class StringTools { * String#frontPadOn(int, char, StringBuilder) */ public static void frontPadOn(String string, int length, char c, StringBuilder sb) { - frontPadOn(string.toCharArray(), length, c, sb); + int stringLength = string.length(); + if (stringLength > length) { + throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); + } + if (stringLength == length) { + sb.append(string); + } else { + frontPadOn_(string, length, c, sb); + } } /** @@ -675,7 +840,7 @@ public final class StringTools { if (stringLength == length) { return string; } - return frontPadInternal(string, length, c); + return frontPad_(string, length, c); } /** @@ -694,7 +859,7 @@ public final class StringTools { if (stringLength == length) { writeStringOn(string, writer); } else { - frontPadOnInternal(string, length, c, writer); + frontPadOn_(string, length, c, writer); } } @@ -714,7 +879,7 @@ public final class StringTools { if (stringLength == length) { sb.append(string); } else { - frontPadOnInternal(string, length, c, sb); + frontPadOn_(string, length, c, sb); } } @@ -734,7 +899,7 @@ public final class StringTools { if (stringLength == length) { sb.append(string); } else { - frontPadOnInternal(string, length, c, sb); + frontPadOn_(string, length, c, sb); } } @@ -798,7 +963,7 @@ public final class StringTools { if (stringLength > length) { return string.substring(stringLength - length); } - return frontPadInternal(string, length, c); + return frontPad_(string, length, c); } /** @@ -810,7 +975,14 @@ public final class StringTools { * String#frontPadOrTruncateOn(int, char, Writer) */ public static void frontPadOrTruncateOn(String string, int length, char c, Writer writer) { - frontPadOrTruncateOn(string.toCharArray(), length, c, writer); + int stringLength = string.length(); + if (stringLength == length) { + writeStringOn(string, writer); + } else if (stringLength > length) { + writeStringOn(string.substring(stringLength - length), writer); + } else { + frontPadOn_(string, length, c, writer); + } } /** @@ -822,7 +994,14 @@ public final class StringTools { * String#frontPadOrTruncateOn(int, char, StringBuffer) */ public static void frontPadOrTruncateOn(String string, int length, char c, StringBuffer sb) { - frontPadOrTruncateOn(string.toCharArray(), length, c, sb); + int stringLength = string.length(); + if (stringLength == length) { + sb.append(string); + } else if (stringLength > length) { + sb.append(string.substring(stringLength - length)); + } else { + frontPadOn_(string, length, c, sb); + } } /** @@ -834,7 +1013,14 @@ public final class StringTools { * String#frontPadOrTruncateOn(int, char, StringBuilder) */ public static void frontPadOrTruncateOn(String string, int length, char c, StringBuilder sb) { - frontPadOrTruncateOn(string.toCharArray(), length, c, sb); + int stringLength = string.length(); + if (stringLength == length) { + sb.append(string); + } else if (stringLength > length) { + sb.append(string.substring(stringLength - length)); + } else { + frontPadOn_(string, length, c, sb); + } } /** @@ -899,7 +1085,7 @@ public final class StringTools { System.arraycopy(string, stringLength - length, result, 0, length); return result; } - return frontPadInternal(string, length, c); + return frontPad_(string, length, c); } /** @@ -917,7 +1103,7 @@ public final class StringTools { } else if (stringLength > length) { writeStringOn(string, stringLength - length, length, writer); } else { - frontPadOnInternal(string, length, c, writer); + frontPadOn_(string, length, c, writer); } } @@ -936,7 +1122,7 @@ public final class StringTools { } else if (stringLength > length) { sb.append(string, stringLength - length, length); } else { - frontPadOnInternal(string, length, c, sb); + frontPadOn_(string, length, c, sb); } } @@ -955,21 +1141,21 @@ public final class StringTools { } else if (stringLength > length) { sb.append(string, stringLength - length, length); } else { - frontPadOnInternal(string, length, c, sb); + frontPadOn_(string, length, c, sb); } } - /** + /* * Front-pad the specified string without validating the parms. */ - private static String frontPadInternal(String string, int length, char c) { - return new String(frontPadInternal(string.toCharArray(), length, c)); + private static String frontPad_(String string, int length, char c) { + return new String(frontPad_(string.toCharArray(), length, c)); } - /** + /* * Zero-pad the specified string without validating the parms. */ - private static char[] frontPadInternal(char[] string, int length, char c) { + private static char[] frontPad_(char[] string, int length, char c) { char[] result = new char[length]; int stringLength = string.length; int padLength = length - stringLength; @@ -978,27 +1164,51 @@ public final class StringTools { return result; } - /** + /* * Pad the specified string without validating the parms. */ - private static void frontPadOnInternal(char[] string, int length, char c, Writer writer) { - writeStringOn(CollectionTools.fill(new char[length - string.length], c), writer); + private static void frontPadOn_(String string, int length, char c, Writer writer) { + fill_(string, length, c, writer); writeStringOn(string, writer); } - /** + /* + * Pad the specified string without validating the parms. + */ + private static void frontPadOn_(char[] string, int length, char c, Writer writer) { + fill_(string, length, c, writer); + writeStringOn(string, writer); + } + + /* * Pad the specified string without validating the parms. */ - private static void frontPadOnInternal(char[] string, int length, char c, StringBuffer sb) { - sb.append(CollectionTools.fill(new char[length - string.length], c)); + private static void frontPadOn_(String string, int length, char c, StringBuffer sb) { + fill_(string, length, c, sb); sb.append(string); } - /** + /* * Pad the specified string without validating the parms. */ - private static void frontPadOnInternal(char[] string, int length, char c, StringBuilder sb) { - sb.append(CollectionTools.fill(new char[length - string.length], c)); + private static void frontPadOn_(char[] string, int length, char c, StringBuffer sb) { + fill_(string, length, c, sb); + sb.append(string); + } + + /* + * Pad the specified string without validating the parms. + */ + private static void frontPadOn_(String string, int length, char c, StringBuilder sb) { + fill_(string, length, c, sb); + sb.append(string); + } + + /* + * Pad the specified string without validating the parms. + */ + private static void frontPadOn_(char[] string, int length, char c, StringBuilder sb) { + fill_(string, length, c, sb); sb.append(string); } @@ -1058,7 +1268,9 @@ public final class StringTools { * the wrap at the front and back of the resulting string. */ public static void wrapOn(String string, char wrap, Writer writer) { - wrapOn(string.toCharArray(), wrap, writer); + writeCharOn(wrap, writer); + writeStringOn(string, writer); + writeCharOn(wrap, writer); } /** @@ -1066,7 +1278,9 @@ public final class StringTools { * the wrap at the front and back of the resulting string. */ public static void wrapOn(String string, char wrap, StringBuffer sb) { - wrapOn(string.toCharArray(), wrap, sb); + sb.append(wrap); + sb.append(string); + sb.append(wrap); } /** @@ -1074,7 +1288,9 @@ public final class StringTools { * the wrap at the front and back of the resulting string. */ public static void wrapOn(String string, char wrap, StringBuilder sb) { - wrapOn(string.toCharArray(), wrap, sb); + sb.append(wrap); + sb.append(string); + sb.append(wrap); } /** @@ -1103,7 +1319,9 @@ public final class StringTools { * the wrap at the front and back of the resulting string. */ public static void wrapOn(String string, String wrap, Writer writer) { - wrapOn(string.toCharArray(), wrap.toCharArray(), writer); + writeStringOn(wrap, writer); + writeStringOn(string, writer); + writeStringOn(wrap, writer); } /** @@ -1111,7 +1329,9 @@ public final class StringTools { * the wrap at the front and back of the resulting string. */ public static void wrapOn(String string, String wrap, StringBuffer sb) { - wrapOn(string.toCharArray(), wrap.toCharArray(), sb); + sb.append(wrap); + sb.append(string); + sb.append(wrap); } /** @@ -1119,7 +1339,9 @@ public final class StringTools { * the wrap at the front and back of the resulting string. */ public static void wrapOn(String string, String wrap, StringBuilder sb) { - wrapOn(string.toCharArray(), wrap.toCharArray(), sb); + sb.append(wrap); + sb.append(string); + sb.append(wrap); } /** @@ -1321,7 +1543,12 @@ public final class StringTools { * String#removeFirstOccurrenceOn(char, Writer) */ public static void removeFirstOccurrenceOn(String string, char c, Writer writer) { - removeFirstOccurrenceOn(string.toCharArray(), c, writer); + int index = string.indexOf(c); + if (index == -1) { + writeStringOn(string, writer); + } else { + removeFirstOccurrenceOn_(string.toCharArray(), c, writer, index); + } } /** @@ -1330,7 +1557,12 @@ public final class StringTools { * String#removeFirstOccurrenceOn(char, StringBuffer) */ public static void removeFirstOccurrenceOn(String string, char c, StringBuffer sb) { - removeFirstOccurrenceOn(string.toCharArray(), c, sb); + int index = string.indexOf(c); + if (index == -1) { + sb.append(string); + } else { + removeFirstOccurrenceOn_(string.toCharArray(), c, sb, index); + } } /** @@ -1339,7 +1571,12 @@ public final class StringTools { * String#removeFirstOccurrenceOn(char, StringBuilder) */ public static void removeFirstOccurrenceOn(String string, char c, StringBuilder sb) { - removeFirstOccurrenceOn(string.toCharArray(), c, sb); + int index = string.indexOf(c); + if (index == -1) { + sb.append(string); + } else { + removeFirstOccurrenceOn_(string.toCharArray(), c, sb, index); + } } /** @@ -1353,19 +1590,18 @@ public final class StringTools { // character not found return string; } - - int len = string.length - 1; - char[] result = new char[len]; + int last = string.length - 1; + char[] result = new char[last]; if (index == 0) { // character found at the front of string - System.arraycopy(string, 1, result, 0, len); - } else if (index == len) { + System.arraycopy(string, 1, result, 0, last); + } else if (index == last) { // character found at the end of string - System.arraycopy(string, 0, result, 0, len); + System.arraycopy(string, 0, result, 0, last); } else { // character found somewhere in the middle of the string System.arraycopy(string, 0, result, 0, index); - System.arraycopy(string, index + 1, result, index, len - index); + System.arraycopy(string, index + 1, result, index, last - index); } return result; } @@ -1378,22 +1614,24 @@ public final class StringTools { public static void removeFirstOccurrenceOn(char[] string, char c, Writer writer) { int index = CollectionTools.indexOf(string, c); if (index == -1) { - // character not found writeStringOn(string, writer); - return; + } else { + removeFirstOccurrenceOn_(string, c, writer, index); } + } - int len = string.length - 1; + private static void removeFirstOccurrenceOn_(char[] string, char c, Writer writer, int index) { + int last = string.length - 1; if (index == 0) { // character found at the front of string - writeStringOn(string, 1, len, writer); - } else if (index == len) { + writeStringOn(string, 1, last, writer); + } else if (index == last) { // character found at the end of string - writeStringOn(string, 0, len, writer); + writeStringOn(string, 0, last, writer); } else { // character found somewhere in the middle of the string writeStringOn(string, 0, index, writer); - writeStringOn(string, index + 1, len - index, writer); + writeStringOn(string, index + 1, last - index, writer); } } @@ -1405,22 +1643,24 @@ public final class StringTools { public static void removeFirstOccurrenceOn(char[] string, char c, StringBuffer sb) { int index = CollectionTools.indexOf(string, c); if (index == -1) { - // character not found sb.append(string); - return; + } else { + removeFirstOccurrenceOn_(string, c, sb, index); } + } - int len = string.length - 1; + private static void removeFirstOccurrenceOn_(char[] string, char c, StringBuffer sb, int index) { + int last = string.length - 1; if (index == 0) { // character found at the front of string - sb.append(string, 1, len); - } else if (index == len) { + sb.append(string, 1, last); + } else if (index == last) { // character found at the end of string - sb.append(string, 0, len); + sb.append(string, 0, last); } else { // character found somewhere in the middle of the string sb.append(string, 0, index); - sb.append(string, index + 1, len - index); + sb.append(string, index + 1, last - index); } } @@ -1432,22 +1672,24 @@ public final class StringTools { public static void removeFirstOccurrenceOn(char[] string, char c, StringBuilder sb) { int index = CollectionTools.indexOf(string, c); if (index == -1) { - // character not found sb.append(string); - return; + } else { + removeFirstOccurrenceOn_(string, c, sb, index); } + } - int len = string.length - 1; + private static void removeFirstOccurrenceOn_(char[] string, char c, StringBuilder sb, int index) { + int last = string.length - 1; if (index == 0) { // character found at the front of string - sb.append(string, 1, len); - } else if (index == len) { + sb.append(string, 1, last); + } else if (index == last) { // character found at the end of string - sb.append(string, 0, len); + sb.append(string, 0, last); } else { // character found somewhere in the middle of the string sb.append(string, 0, index); - sb.append(string, index + 1, len - index); + sb.append(string, index + 1, last - index); } } @@ -1457,7 +1699,8 @@ public final class StringTools { * String#removeAllOccurrences(char) */ public static String removeAllOccurrences(String string, char c) { - return new String(removeAllOccurrences(string.toCharArray(), c)); + int first = string.indexOf(c); + return (first == -1) ? string : new String(removeAllOccurrences_(string.toCharArray(), c, first)); } /** @@ -1466,7 +1709,12 @@ public final class StringTools { * String#removeAllOccurrencesOn(char, Writer) */ public static void removeAllOccurrencesOn(String string, char c, Writer writer) { - removeAllOccurrencesOn(string.toCharArray(), c, writer); + int first = string.indexOf(c); + if (first == -1) { + writeStringOn(string, writer); + } else { + removeAllOccurrencesOn_(string.toCharArray(), c, first, writer); + } } /** @@ -1475,7 +1723,12 @@ public final class StringTools { * String#removeAllOccurrencesOn(char, StringBuffer) */ public static void removeAllOccurrencesOn(String string, char c, StringBuffer sb) { - removeAllOccurrencesOn(string.toCharArray(), c, sb); + int first = string.indexOf(c); + if (first == -1) { + sb.append(string); + } else { + removeAllOccurrencesOn_(string.toCharArray(), c, first, sb); + } } /** @@ -1484,7 +1737,12 @@ public final class StringTools { * String#removeAllOccurrencesOn(char, StringBuilder) */ public static void removeAllOccurrencesOn(String string, char c, StringBuilder sb) { - removeAllOccurrencesOn(string.toCharArray(), c, sb); + int first = string.indexOf(c); + if (first == -1) { + sb.append(string); + } else { + removeAllOccurrencesOn_(string.toCharArray(), c, first, sb); + } } /** @@ -1493,12 +1751,17 @@ public final class StringTools { * String#removeAllOccurrences(char) */ public static char[] removeAllOccurrences(char[] string, char c) { + int first = CollectionTools.indexOf(string, c); + return (first == -1) ? string : removeAllOccurrences_(string, c, first); + } + + /* + * The index of the first matching character is passed in. + */ + private static char[] removeAllOccurrences_(char[] string, char c, int first) { StringBuilder sb = new StringBuilder(string.length); - removeAllOccurrencesOn(string, c, sb); - int len = sb.length(); - char[] result = new char[len]; - sb.getChars(0, len, result, 0); - return result; + removeAllOccurrencesOn_(string, c, first, sb); + return convertToCharArray(sb); } /** @@ -1508,11 +1771,22 @@ public final class StringTools { * String#removeAllOccurrencesOn(char, Writer) */ public static void removeAllOccurrencesOn(char[] string, char c, Writer writer) { - removeAllOccurrencesOnInternal(string, c, writer); + int first = CollectionTools.indexOf(string, c); + if (first == -1) { + writeStringOn(string, writer); + } else { + removeAllOccurrencesOn_(string, c, first, writer); + } } - private static void removeAllOccurrencesOnInternal(char[] string, char c, Writer writer) { - for (char d : string) { + /* + * The index of the first matching character is passed in. + */ + private static void removeAllOccurrencesOn_(char[] string, char c, int first, Writer writer) { + writeStringOn(string, 0, first, writer); + int len = string.length; + for (int i = first; i < len; i++) { + char d = string[i]; if (d != c) { writeCharOn(d, writer); } @@ -1526,7 +1800,22 @@ public final class StringTools { * String#removeAllOccurrencesOn(char, StringBuffer) */ public static void removeAllOccurrencesOn(char[] string, char c, StringBuffer sb) { - for (char d : string) { + int first = CollectionTools.indexOf(string, c); + if (first == -1) { + sb.append(string); + } else { + removeAllOccurrencesOn_(string, c, first, sb); + } + } + + /* + * The index of the first matching character is passed in. + */ + private static void removeAllOccurrencesOn_(char[] string, char c, int first, StringBuffer sb) { + sb.append(string, 0, first); + int len = string.length; + for (int i = first; i < len; i++) { + char d = string[i]; if (d != c) { sb.append(d); } @@ -1536,11 +1825,26 @@ public final class StringTools { /** * Remove all occurrences of the specified character * from the specified string and append the result to the - * specified string buffer. + * specified string builder. * String#removeAllOccurrencesOn(char, StringBuilder) */ public static void removeAllOccurrencesOn(char[] string, char c, StringBuilder sb) { - for (char d : string) { + int first = CollectionTools.indexOf(string, c); + if (first == -1) { + sb.append(string); + } else { + removeAllOccurrencesOn_(string, c, first, sb); + } + } + + /* + * The index of the first matching character is passed in. + */ + private static void removeAllOccurrencesOn_(char[] string, char c, int first, StringBuilder sb) { + sb.append(string, 0, first); + int len = string.length; + for (int i = first; i < len; i++) { + char d = string[i]; if (d != c) { sb.append(d); } @@ -1555,6 +1859,246 @@ public final class StringTools { return removeAllOccurrences(string, ' '); } + /** + * Remove all the spaces + * from the specified string and write the result to the specified writer. + * String#removeAllSpacesOn(Writer) + */ + public static void removeAllSpacesOn(String string, Writer writer) { + removeAllOccurrencesOn(string, ' ', writer); + } + + /** + * Remove all the spaces + * from the specified string and write the result to the specified + * string buffer. + * String#removeAllSpacesOn(StringBuffer) + */ + public static void removeAllSpacesOn(String string, StringBuffer sb) { + removeAllOccurrencesOn(string, ' ', sb); + } + + /** + * Remove all the spaces + * from the specified string and write the result to the specified + * string builder. + * String#removeAllSpacesOn(StringBuilder) + */ + public static void removeAllSpacesOn(String string, StringBuilder sb) { + removeAllOccurrencesOn(string, ' ', sb); + } + + /** + * Remove all the spaces from the specified string and return the result. + * String#removeAllSpaces() + */ + public static char[] removeAllSpaces(char[] string) { + return removeAllOccurrences(string, ' '); + } + + /** + * Remove all the spaces + * from the specified string and write the result to the + * specified writer. + * String#removeAllSpacesOn(Writer) + */ + public static void removeAllSpacesOn(char[] string, Writer writer) { + removeAllOccurrencesOn(string, ' ', writer); + } + + /** + * Remove all the spaces + * from the specified string and append the result to the + * specified string buffer. + * String#removeAllSpacesOn(StringBuffer) + */ + public static void removeAllSpacesOn(char[] string, StringBuffer sb) { + removeAllOccurrencesOn(string, ' ', sb); + } + + /** + * Remove all the spaces + * from the specified string and append the result to the + * specified string builder. + * String#removeAllSpacesOn(StringBuilder) + */ + public static void removeAllSpacesOn(char[] string, StringBuilder sb) { + removeAllOccurrencesOn(string, ' ', sb); + } + + /** + * Remove all the whitespace from the specified string and return the result. + * String#removeAllWhitespace() + */ + public static String removeAllWhitespace(String string) { + char[] string2 = string.toCharArray(); + int first = indexOfWhitespace_(string2); + return (first == -1) ? string : new String(removeAllWhitespace_(string2, first)); + } + + /** + * Remove all the whitespace + * from the specified string and append the result to the + * specified writer. + * String#removeAllWhitespaceOn(Writer) + */ + public static void removeAllWhitespaceOn(String string, Writer writer) { + char[] string2 = string.toCharArray(); + int first = indexOfWhitespace_(string2); + if (first == -1) { + writeStringOn(string, writer); + } else { + removeAllWhitespaceOn_(string2, first, writer); + } + } + + /** + * Remove all the whitespace + * from the specified string and append the result to the + * specified string buffer. + * String#removeAllWhitespaceOn(StringBuffer) + */ + public static void removeAllWhitespaceOn(String string, StringBuffer sb) { + char[] string2 = string.toCharArray(); + int first = indexOfWhitespace_(string2); + if (first == -1) { + sb.append(string); + } else { + removeAllWhitespaceOn_(string2, first, sb); + } + } + + /** + * Remove all the whitespace + * from the specified string and append the result to the + * specified string builder. + * String#removeAllWhitespaceOn(StringBuilder) + */ + public static void removeAllWhitespaceOn(String string, StringBuilder sb) { + char[] string2 = string.toCharArray(); + int first = indexOfWhitespace_(string2); + if (first == -1) { + sb.append(string); + } else { + removeAllWhitespaceOn_(string2, first, sb); + } + } + + /** + * Remove all the whitespace from the specified string and return the result. + * String#removeAllWhitespace() + */ + public static char[] removeAllWhitespace(char[] string) { + int first = indexOfWhitespace_(string); + return (first == -1) ? string : removeAllWhitespace_(string, first); + } + + private static int indexOfWhitespace_(char[] string) { + int len = string.length; + for (int i = 0; i < len; i++) { + if (Character.isWhitespace(string[i])) { + return i; + } + } + return -1; + } + + /* + * The index of the first non-whitespace character is passed in. + */ + private static char[] removeAllWhitespace_(char[] string, int first) { + StringBuilder sb = new StringBuilder(string.length); + removeAllWhitespaceOn_(string, first, sb); + return convertToCharArray(sb); + } + + /** + * Remove all the whitespace + * from the specified string and append the result to the + * specified writer. + * String#removeAllWhitespaceOn(Writer) + */ + public static void removeAllWhitespaceOn(char[] string, Writer writer) { + int first = indexOfWhitespace_(string); + if (first == -1) { + writeStringOn(string, writer); + } else { + removeAllWhitespaceOn_(string, first, writer); + } + } + + /* + * The index of the first non-whitespace character is passed in. + */ + private static void removeAllWhitespaceOn_(char[] string, int first, Writer writer) { + writeStringOn(string, 0, first, writer); + int len = string.length; + for (int i = first; i < len; i++) { + char c = string[i]; + if ( ! Character.isWhitespace(c)) { + writeCharOn(c, writer); + } + } + } + + /** + * Remove all the whitespace + * from the specified string and append the result to the + * specified string buffer. + * String#removeAllWhitespaceOn(StringBuffer) + */ + public static void removeAllWhitespaceOn(char[] string, StringBuffer sb) { + int first = indexOfWhitespace_(string); + if (first == -1) { + sb.append(string); + } else { + removeAllWhitespaceOn_(string, first, sb); + } + } + + /* + * The index of the first non-whitespace character is passed in. + */ + private static void removeAllWhitespaceOn_(char[] string, int first, StringBuffer sb) { + sb.append(string, 0, first); + int len = string.length; + for (int i = first; i < len; i++) { + char c = string[i]; + if ( ! Character.isWhitespace(c)) { + sb.append(c); + } + } + } + + /** + * Remove all the whitespace + * from the specified string and append the result to the + * specified string builder. + * String#removeAllWhitespaceOn(StringBuilder) + */ + public static void removeAllWhitespaceOn(char[] string, StringBuilder sb) { + int first = indexOfWhitespace_(string); + if (first == -1) { + sb.append(string); + } else { + removeAllWhitespaceOn_(string, first, sb); + } + } + + /* + * The index of the first non-whitespace character is passed in. + */ + private static void removeAllWhitespaceOn_(char[] string, int first, StringBuilder sb) { + sb.append(string, 0, first); + int len = string.length; + for (int i = first; i < len; i++) { + char c = string[i]; + if ( ! Character.isWhitespace(c)) { + sb.append(c); + } + } + } + // ********** common prefix ********** @@ -1570,7 +2114,7 @@ public final class StringTools { * Return the length of the common prefix shared by the specified strings. */ public static int commonPrefixLength(char[] s1, char[] s2) { - return commonPrefixLengthInternal(s1, s2, Math.min(s1.length, s2.length)); + return commonPrefixLength_(s1, s2, Math.min(s1.length, s2.length)); } /** @@ -1587,15 +2131,15 @@ public final class StringTools { * but limit the length to the specified maximum. */ public static int commonPrefixLength(char[] s1, char[] s2, int max) { - return commonPrefixLengthInternal(s1, s2, Math.min(max, Math.min(s1.length, s2.length))); + return commonPrefixLength_(s1, s2, Math.min(max, Math.min(s1.length, s2.length))); } - /** + /* * Return the length of the common prefix shared by the specified strings; * but limit the length to the specified maximum. Assume the specified * maximum is less than the lengths of the specified strings. */ - private static int commonPrefixLengthInternal(char[] s1, char[] s2, int max) { + private static int commonPrefixLength_(char[] s1, char[] s2, int max) { for (int i = 0; i < max; i++) { if (s1[i] != s2[i]) { return i; @@ -1607,10 +2151,10 @@ public final class StringTools { // ********** capitalization ********** - /** + /* * no zero-length check or lower case check */ - private static char[] capitalizeInternal(char[] string) { + private static char[] capitalize_(char[] string) { string[0] = Character.toUpperCase(string[0]); return string; } @@ -1623,7 +2167,7 @@ public final class StringTools { if ((string.length == 0) || Character.isUpperCase(string[0])) { return string; } - return capitalizeInternal(string); + return capitalize_(string); } /** @@ -1634,21 +2178,13 @@ public final class StringTools { if ((string.length() == 0) || Character.isUpperCase(string.charAt(0))) { return string; } - return new String(capitalizeInternal(string.toCharArray())); + return new String(capitalize_(string.toCharArray())); } - /** + /* * no zero-length check or upper case check */ - private static void capitalizeOnInternal(char[] string, StringBuffer sb) { - sb.append(Character.toUpperCase(string[0])); - sb.append(string, 1, string.length - 1); - } - - /** - * no zero-length check or upper case check - */ - private static void capitalizeOnInternal(char[] string, StringBuilder sb) { + private static void capitalizeOn_(char[] string, StringBuffer sb) { sb.append(Character.toUpperCase(string[0])); sb.append(string, 1, string.length - 1); } @@ -1664,45 +2200,53 @@ public final class StringTools { if (Character.isUpperCase(string[0])) { sb.append(string); } else { - capitalizeOnInternal(string, sb); + capitalizeOn_(string, sb); } } /** * Append the specified string to the specified string buffer * with its first letter capitalized. + * String#capitalizeOn(StringBuffer) */ - public static void capitalizeOn(char[] string, StringBuilder sb) { - if (string.length == 0) { + public static void capitalizeOn(String string, StringBuffer sb) { + if (string.length() == 0) { return; } - if (Character.isUpperCase(string[0])) { + if (Character.isUpperCase(string.charAt(0))) { sb.append(string); } else { - capitalizeOnInternal(string, sb); + capitalizeOn_(string.toCharArray(), sb); } } + /* + * no zero-length check or upper case check + */ + private static void capitalizeOn_(char[] string, StringBuilder sb) { + sb.append(Character.toUpperCase(string[0])); + sb.append(string, 1, string.length - 1); + } + /** - * Append the specified string to the specified string buffer + * Append the specified string to the specified string builder * with its first letter capitalized. - * String#capitalizeOn(StringBuffer) */ - public static void capitalizeOn(String string, StringBuffer sb) { - if (string.length() == 0) { + public static void capitalizeOn(char[] string, StringBuilder sb) { + if (string.length == 0) { return; } - if (Character.isUpperCase(string.charAt(0))) { + if (Character.isUpperCase(string[0])) { sb.append(string); } else { - capitalizeOnInternal(string.toCharArray(), sb); + capitalizeOn_(string, sb); } } /** - * Append the specified string to the specified string buffer + * Append the specified string to the specified string builder * with its first letter capitalized. - * String#capitalizeOn(StringBuilder) + * String#capitalizeOn(StringBuffer) */ public static void capitalizeOn(String string, StringBuilder sb) { if (string.length() == 0) { @@ -1711,14 +2255,14 @@ public final class StringTools { if (Character.isUpperCase(string.charAt(0))) { sb.append(string); } else { - capitalizeOnInternal(string.toCharArray(), sb); + capitalizeOn_(string.toCharArray(), sb); } } - /** + /* * no zero-length check or upper case check */ - private static void capitalizeOnInternal(char[] string, Writer writer) { + private static void capitalizeOn_(char[] string, Writer writer) { writeCharOn(Character.toUpperCase(string[0]), writer); writeStringOn(string, 1, string.length - 1, writer); } @@ -1734,7 +2278,7 @@ public final class StringTools { if (Character.isUpperCase(string[0])) { writeStringOn(string, writer); } else { - capitalizeOnInternal(string, writer); + capitalizeOn_(string, writer); } } @@ -1750,19 +2294,19 @@ public final class StringTools { if (Character.isUpperCase(string.charAt(0))) { writeStringOn(string, writer); } else { - capitalizeOnInternal(string.toCharArray(), writer); + capitalizeOn_(string.toCharArray(), writer); } } - /** + /* * no zero-length check or lower case check */ - private static char[] uncapitalizeInternal(char[] string) { + private static char[] uncapitalize_(char[] string) { string[0] = Character.toLowerCase(string[0]); return string; } - private static boolean stringNeedNotBeUncapitalized(char[] string) { + private static boolean stringNeedNotBeUncapitalized_(char[] string) { if (string.length == 0) { return true; } @@ -1786,13 +2330,13 @@ public final class StringTools { * in which case the string is returned unchanged.) */ public static char[] uncapitalize(char[] string) { - if (stringNeedNotBeUncapitalized(string)) { + if (stringNeedNotBeUncapitalized_(string)) { return string; } - return uncapitalizeInternal(string); + return uncapitalize_(string); } - private static boolean stringNeedNotBeUncapitalized(String string) { + private static boolean stringNeedNotBeUncapitalized_(String string) { if (string.length() == 0) { return true; } @@ -1816,24 +2360,16 @@ public final class StringTools { * String#uncapitalize() */ public static String uncapitalize(String string) { - if (stringNeedNotBeUncapitalized(string)) { + if (stringNeedNotBeUncapitalized_(string)) { return string; } - return new String(uncapitalizeInternal(string.toCharArray())); + return new String(uncapitalize_(string.toCharArray())); } - /** + /* * no zero-length check or lower case check */ - private static void uncapitalizeOnInternal(char[] string, StringBuffer sb) { - sb.append(Character.toLowerCase(string[0])); - sb.append(string, 1, string.length - 1); - } - - /** - * no zero-length check or lower case check - */ - private static void uncapitalizeOnInternal(char[] string, StringBuilder sb) { + private static void uncapitalizeOn_(char[] string, StringBuffer sb) { sb.append(Character.toLowerCase(string[0])); sb.append(string, 1, string.length - 1); } @@ -1845,10 +2381,10 @@ public final class StringTools { * in which case the string is returned unchanged.) */ public static void uncapitalizeOn(char[] string, StringBuffer sb) { - if (stringNeedNotBeUncapitalized(string)) { + if (stringNeedNotBeUncapitalized_(string)) { sb.append(string); } else { - uncapitalizeOnInternal(string, sb); + uncapitalizeOn_(string, sb); } } @@ -1857,49 +2393,57 @@ public final class StringTools { * with its first letter converted to lower case. * (Unless both the first and second letters are upper case, * in which case the string is returned unchanged.) + * String#uncapitalizeOn(StringBuffer) */ - public static void uncapitalizeOn(char[] string, StringBuilder sb) { - if (stringNeedNotBeUncapitalized(string)) { + public static void uncapitalizeOn(String string, StringBuffer sb) { + if (stringNeedNotBeUncapitalized_(string)) { sb.append(string); } else { - uncapitalizeOnInternal(string, sb); + uncapitalizeOn_(string.toCharArray(), sb); } } + /* + * no zero-length check or lower case check + */ + private static void uncapitalizeOn_(char[] string, StringBuilder sb) { + sb.append(Character.toLowerCase(string[0])); + sb.append(string, 1, string.length - 1); + } + /** - * Append the specified string to the specified string buffer + * Append the specified string to the specified string builder * with its first letter converted to lower case. * (Unless both the first and second letters are upper case, * in which case the string is returned unchanged.) - * String#uncapitalizeOn(StringBuffer) */ - public static void uncapitalizeOn(String string, StringBuffer sb) { - if (stringNeedNotBeUncapitalized(string)) { + public static void uncapitalizeOn(char[] string, StringBuilder sb) { + if (stringNeedNotBeUncapitalized_(string)) { sb.append(string); } else { - uncapitalizeOnInternal(string.toCharArray(), sb); + uncapitalizeOn_(string, sb); } } /** - * Append the specified string to the specified string buffer + * Append the specified string to the specified string builder * with its first letter converted to lower case. * (Unless both the first and second letters are upper case, * in which case the string is returned unchanged.) - * String#uncapitalizeOn(StringBuilder) + * String#uncapitalizeOn(StringBuffer) */ public static void uncapitalizeOn(String string, StringBuilder sb) { - if (stringNeedNotBeUncapitalized(string)) { + if (stringNeedNotBeUncapitalized_(string)) { sb.append(string); } else { - uncapitalizeOnInternal(string.toCharArray(), sb); + uncapitalizeOn_(string.toCharArray(), sb); } } - /** + /* * no zero-length check or upper case check */ - private static void uncapitalizeOnInternal(char[] string, Writer writer) { + private static void uncapitalizeOn_(char[] string, Writer writer) { writeCharOn(Character.toLowerCase(string[0]), writer); writeStringOn(string, 1, string.length - 1, writer); } @@ -1911,10 +2455,10 @@ public final class StringTools { * in which case the string is returned unchanged.) */ public static void uncapitalizeOn(char[] string, Writer writer) { - if (stringNeedNotBeUncapitalized(string)) { + if (stringNeedNotBeUncapitalized_(string)) { writeStringOn(string, writer); } else { - uncapitalizeOnInternal(string, writer); + uncapitalizeOn_(string, writer); } } @@ -1926,10 +2470,10 @@ public final class StringTools { * String#uncapitalizeOn(Writer) */ public static void uncapitalizeOn(String string, Writer writer) { - if (stringNeedNotBeUncapitalized(string)) { + if (stringNeedNotBeUncapitalized_(string)) { writeStringOn(string, writer); } else { - uncapitalizeOnInternal(string.toCharArray(), writer); + uncapitalizeOn_(string.toCharArray(), writer); } } @@ -1997,7 +2541,7 @@ public final class StringTools { if ((string == null) || (string.length() == 0)) { return true; } - return stringIsEmptyInternal(string.toCharArray()); + return stringIsEmpty_(string.toCharArray()); } /** @@ -2008,10 +2552,10 @@ public final class StringTools { if ((string == null) || (string.length == 0)) { return true; } - return stringIsEmptyInternal(string); + return stringIsEmpty_(string); } - private static boolean stringIsEmptyInternal(char[] s) { + private static boolean stringIsEmpty_(char[] s) { for (int i = s.length; i-- > 0; ) { if ( ! Character.isWhitespace(s[i])) { return false; @@ -2098,7 +2642,11 @@ public final class StringTools { * "largeProject" -> "LARGE_PROJECT" */ public static String convertCamelCaseToAllCaps(String camelCaseString) { - return new String(convertCamelCaseToAllCaps(camelCaseString.toCharArray())); + int len = camelCaseString.length(); + if (len == 0) { + return camelCaseString; + } + return new String(convertCamelCaseToAllCaps_(camelCaseString.toCharArray(), len)); } /** @@ -2110,8 +2658,12 @@ public final class StringTools { if (len == 0) { return camelCaseString; } + return convertCamelCaseToAllCaps_(camelCaseString, len); + } + + private static char[] convertCamelCaseToAllCaps_(char[] camelCaseString, int len) { StringBuilder sb = new StringBuilder(len * 2); - convertCamelCaseToAllCapsOnInternal(camelCaseString, len, sb); + convertCamelCaseToAllCapsOn_(camelCaseString, len, sb); return convertToCharArray(sb); } @@ -2120,25 +2672,9 @@ public final class StringTools { * "largeProject" -> "LARGE_PROJECT" */ public static void convertCamelCaseToAllCapsOn(String camelCaseString, StringBuffer sb) { - convertCamelCaseToAllCapsOn(camelCaseString.toCharArray(), sb); - } - - /** - * Convert the specified "camel case" string to an "all caps" string: - * "largeProject" -> "LARGE_PROJECT" - */ - public static void convertCamelCaseToAllCapsOn(String camelCaseString, StringBuilder sb) { - convertCamelCaseToAllCapsOn(camelCaseString.toCharArray(), sb); - } - - /** - * Convert the specified "camel case" string to an "all caps" string: - * "largeProject" -> "LARGE_PROJECT" - */ - public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, StringBuffer sb) { - int len = camelCaseString.length; + int len = camelCaseString.length(); if (len != 0) { - convertCamelCaseToAllCapsOnInternal(camelCaseString, len, sb); + convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), len, sb); } } @@ -2146,21 +2682,21 @@ public final class StringTools { * Convert the specified "camel case" string to an "all caps" string: * "largeProject" -> "LARGE_PROJECT" */ - public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, StringBuilder sb) { + public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, StringBuffer sb) { int len = camelCaseString.length; if (len != 0) { - convertCamelCaseToAllCapsOnInternal(camelCaseString, len, sb); + convertCamelCaseToAllCapsOn_(camelCaseString, len, sb); } } - private static void convertCamelCaseToAllCapsOnInternal(char[] camelCaseString, int len, StringBuffer sb) { + private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int len, StringBuffer sb) { char prev = 0; // assume 0 is not a valid char char c = 0; char next = camelCaseString[0]; for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len! c = next; next = ((i == len) ? 0 : camelCaseString[i]); - if (camelCaseWordBreak(prev, c, next)) { + if (camelCaseWordBreak_(prev, c, next)) { sb.append('_'); } sb.append(Character.toUpperCase(c)); @@ -2168,14 +2704,36 @@ public final class StringTools { } } - private static void convertCamelCaseToAllCapsOnInternal(char[] camelCaseString, int len, StringBuilder sb) { + /** + * Convert the specified "camel case" string to an "all caps" string: + * "largeProject" -> "LARGE_PROJECT" + */ + public static void convertCamelCaseToAllCapsOn(String camelCaseString, StringBuilder sb) { + int len = camelCaseString.length(); + if (len != 0) { + convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), len, sb); + } + } + + /** + * Convert the specified "camel case" string to an "all caps" string: + * "largeProject" -> "LARGE_PROJECT" + */ + public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, StringBuilder sb) { + int len = camelCaseString.length; + if (len != 0) { + convertCamelCaseToAllCapsOn_(camelCaseString, len, sb); + } + } + + private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int len, StringBuilder sb) { char prev = 0; // assume 0 is not a valid char char c = 0; char next = camelCaseString[0]; for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len! c = next; next = ((i == len) ? 0 : camelCaseString[i]); - if (camelCaseWordBreak(prev, c, next)) { + if (camelCaseWordBreak_(prev, c, next)) { sb.append('_'); } sb.append(Character.toUpperCase(c)); @@ -2188,7 +2746,10 @@ public final class StringTools { * "largeProject" -> "LARGE_PROJECT" */ public static void convertCamelCaseToAllCapsOn(String camelCaseString, Writer writer) { - convertCamelCaseToAllCapsOn(camelCaseString.toCharArray(), writer); + int len = camelCaseString.length(); + if (len != 0) { + convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), len, writer); + } } /** @@ -2198,18 +2759,18 @@ public final class StringTools { public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, Writer writer) { int len = camelCaseString.length; if (len != 0) { - convertCamelCaseToAllCapsOnInternal(camelCaseString, len, writer); + convertCamelCaseToAllCapsOn_(camelCaseString, len, writer); } } - private static void convertCamelCaseToAllCapsOnInternal(char[] camelCaseString, int len, Writer writer) { + private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int len, Writer writer) { char prev = 0; // assume 0 is not a valid char char c = 0; char next = camelCaseString[0]; for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len! c = next; next = ((i == len) ? 0 : camelCaseString[i]); - if (camelCaseWordBreak(prev, c, next)) { + if (camelCaseWordBreak_(prev, c, next)) { writeCharOn('_', writer); } writeCharOn(Character.toUpperCase(c), writer); @@ -2223,7 +2784,11 @@ public final class StringTools { * Limit the resulting string to the specified maximum length. */ public static String convertCamelCaseToAllCaps(String camelCaseString, int maxLength) { - return new String(convertCamelCaseToAllCaps(camelCaseString.toCharArray(), maxLength)); + int len = camelCaseString.length(); + if ((len == 0) || (maxLength == 0)) { + return camelCaseString; + } + return new String(convertCamelCaseToAllCaps_(camelCaseString.toCharArray(), maxLength, len)); } /** @@ -2236,8 +2801,12 @@ public final class StringTools { if ((len == 0) || (maxLength == 0)) { return camelCaseString; } + return convertCamelCaseToAllCaps_(camelCaseString, maxLength, len); + } + + private static char[] convertCamelCaseToAllCaps_(char[] camelCaseString, int maxLength, int len) { StringBuilder sb = new StringBuilder(maxLength); - convertCamelCaseToAllCapsOnInternal(camelCaseString, maxLength, len, sb); + convertCamelCaseToAllCapsOn_(camelCaseString, maxLength, len, sb); return convertToCharArray(sb); } @@ -2247,27 +2816,9 @@ public final class StringTools { * Limit the resulting string to the specified maximum length. */ public static void convertCamelCaseToAllCapsOn(String camelCaseString, int maxLength, StringBuffer sb) { - convertCamelCaseToAllCapsOn(camelCaseString.toCharArray(), maxLength, sb); - } - - /** - * Convert the specified "camel case" string to an "all caps" string: - * "largeProject" -> "LARGE_PROJECT" - * Limit the resulting string to the specified maximum length. - */ - public static void convertCamelCaseToAllCapsOn(String camelCaseString, int maxLength, StringBuilder sb) { - convertCamelCaseToAllCapsOn(camelCaseString.toCharArray(), maxLength, sb); - } - - /** - * Convert the specified "camel case" string to an "all caps" string: - * "largeProject" -> "LARGE_PROJECT" - * Limit the resulting string to the specified maximum length. - */ - public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, int maxLength, StringBuffer sb) { - int len = camelCaseString.length; + int len = camelCaseString.length(); if ((len != 0) && (maxLength != 0)) { - convertCamelCaseToAllCapsOnInternal(camelCaseString, maxLength, len, sb); + convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), maxLength, len, sb); } } @@ -2276,21 +2827,21 @@ public final class StringTools { * "largeProject" -> "LARGE_PROJECT" * Limit the resulting string to the specified maximum length. */ - public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, int maxLength, StringBuilder sb) { + public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, int maxLength, StringBuffer sb) { int len = camelCaseString.length; if ((len != 0) && (maxLength != 0)) { - convertCamelCaseToAllCapsOnInternal(camelCaseString, maxLength, len, sb); + convertCamelCaseToAllCapsOn_(camelCaseString, maxLength, len, sb); } } - private static void convertCamelCaseToAllCapsOnInternal(char[] camelCaseString, int maxLength, int len, StringBuffer sb) { + private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int maxLength, int len, StringBuffer sb) { char prev = 0; // assume 0 is not a valid char char c = 0; char next = camelCaseString[0]; for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len! c = next; next = ((i == len) ? 0 : camelCaseString[i]); - if (camelCaseWordBreak(prev, c, next)) { + if (camelCaseWordBreak_(prev, c, next)) { sb.append('_'); if (sb.length() == maxLength) { return; @@ -2304,14 +2855,38 @@ public final class StringTools { } } - private static void convertCamelCaseToAllCapsOnInternal(char[] camelCaseString, int maxLength, int len, StringBuilder sb) { + /** + * Convert the specified "camel case" string to an "all caps" string: + * "largeProject" -> "LARGE_PROJECT" + * Limit the resulting string to the specified maximum length. + */ + public static void convertCamelCaseToAllCapsOn(String camelCaseString, int maxLength, StringBuilder sb) { + int len = camelCaseString.length(); + if ((len != 0) && (maxLength != 0)) { + convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), maxLength, len, sb); + } + } + + /** + * Convert the specified "camel case" string to an "all caps" string: + * "largeProject" -> "LARGE_PROJECT" + * Limit the resulting string to the specified maximum length. + */ + public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, int maxLength, StringBuilder sb) { + int len = camelCaseString.length; + if ((len != 0) && (maxLength != 0)) { + convertCamelCaseToAllCapsOn_(camelCaseString, maxLength, len, sb); + } + } + + private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int maxLength, int len, StringBuilder sb) { char prev = 0; // assume 0 is not a valid char char c = 0; char next = camelCaseString[0]; for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len! c = next; next = ((i == len) ? 0 : camelCaseString[i]); - if (camelCaseWordBreak(prev, c, next)) { + if (camelCaseWordBreak_(prev, c, next)) { sb.append('_'); if (sb.length() == maxLength) { return; @@ -2331,7 +2906,10 @@ public final class StringTools { * Limit the resulting string to the specified maximum length. */ public static void convertCamelCaseToAllCapsOn(String camelCaseString, int maxLength, Writer writer) { - convertCamelCaseToAllCapsOn(camelCaseString.toCharArray(), maxLength, writer); + int len = camelCaseString.length(); + if ((len != 0) && (maxLength != 0)) { + convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), maxLength, len, writer); + } } /** @@ -2342,11 +2920,11 @@ public final class StringTools { public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, int maxLength, Writer writer) { int len = camelCaseString.length; if ((len != 0) && (maxLength != 0)) { - convertCamelCaseToAllCapsOnInternal(camelCaseString, maxLength, len, writer); + convertCamelCaseToAllCapsOn_(camelCaseString, maxLength, len, writer); } } - private static void convertCamelCaseToAllCapsOnInternal(char[] camelCaseString, int maxLength, int len, Writer writer) { + private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int maxLength, int len, Writer writer) { char prev = 0; // assume 0 is not a valid char char c = 0; char next = camelCaseString[0]; @@ -2354,7 +2932,7 @@ public final class StringTools { for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len! c = next; next = ((i == len) ? 0 : camelCaseString[i]); - if (camelCaseWordBreak(prev, c, next)) { + if (camelCaseWordBreak_(prev, c, next)) { writeCharOn('_', writer); if (++writerLength == maxLength) { return; @@ -2368,7 +2946,7 @@ public final class StringTools { } } - /** + /* * Return whether the specified series of characters occur at * a "camel case" work break: * "*aa" -> false @@ -2383,7 +2961,7 @@ public final class StringTools { * "AAa" -> true * where '*' == any char */ - private static boolean camelCaseWordBreak(char prev, char c, char next) { + private static boolean camelCaseWordBreak_(char prev, char c, char next) { if (prev == 0) { // start of string return false; } @@ -2405,7 +2983,7 @@ public final class StringTools { * Capitalize the first letter. */ public static String convertUnderscoresToCamelCase(String underscoreString) { - return new String(convertUnderscoresToCamelCase(underscoreString.toCharArray())); + return convertUnderscoresToCamelCase(underscoreString, true); } /** @@ -2423,7 +3001,11 @@ public final class StringTools { * Optionally capitalize the first letter. */ public static String convertUnderscoresToCamelCase(String underscoreString, boolean capitalizeFirstLetter) { - return new String(convertUnderscoresToCamelCase(underscoreString.toCharArray(), capitalizeFirstLetter)); + int len = underscoreString.length(); + if (len == 0) { + return underscoreString; + } + return new String(convertUnderscoresToCamelCase_(underscoreString.toCharArray(), capitalizeFirstLetter, len)); } /** @@ -2436,8 +3018,12 @@ public final class StringTools { if (len == 0) { return underscoreString; } + return convertUnderscoresToCamelCase_(underscoreString, capitalizeFirstLetter, len); + } + + private static char[] convertUnderscoresToCamelCase_(char[] underscoreString, boolean capitalizeFirstLetter, int len) { StringBuilder sb = new StringBuilder(len); - convertUnderscoresToCamelCaseOnInternal(underscoreString, capitalizeFirstLetter, len, sb); + convertUnderscoresToCamelCaseOn_(underscoreString, capitalizeFirstLetter, len, sb); return convertToCharArray(sb); } @@ -2447,27 +3033,9 @@ public final class StringTools { * Optionally capitalize the first letter. */ public static void convertUnderscoresToCamelCaseOn(String underscoreString, boolean capitalizeFirstLetter, StringBuffer sb) { - convertUnderscoresToCamelCaseOn(underscoreString.toCharArray(), capitalizeFirstLetter, sb); - } - - /** - * Convert the specified "underscore" string to a "camel case" string: - * "LARGE_PROJECT" -> "largeProject" - * Optionally capitalize the first letter. - */ - public static void convertUnderscoresToCamelCaseOn(String underscoreString, boolean capitalizeFirstLetter, StringBuilder sb) { - convertUnderscoresToCamelCaseOn(underscoreString.toCharArray(), capitalizeFirstLetter, sb); - } - - /** - * Convert the specified "underscore" string to a "camel case" string: - * "LARGE_PROJECT" -> "largeProject" - * Optionally capitalize the first letter. - */ - public static void convertUnderscoresToCamelCaseOn(char[] underscoreString, boolean capitalizeFirstLetter, StringBuffer sb) { - int len = underscoreString.length; + int len = underscoreString.length(); if (len != 0) { - convertUnderscoresToCamelCaseOnInternal(underscoreString, capitalizeFirstLetter, len, sb); + convertUnderscoresToCamelCaseOn_(underscoreString.toCharArray(), capitalizeFirstLetter, len, sb); } } @@ -2476,14 +3044,14 @@ public final class StringTools { * "LARGE_PROJECT" -> "largeProject" * Optionally capitalize the first letter. */ - public static void convertUnderscoresToCamelCaseOn(char[] underscoreString, boolean capitalizeFirstLetter, StringBuilder sb) { + public static void convertUnderscoresToCamelCaseOn(char[] underscoreString, boolean capitalizeFirstLetter, StringBuffer sb) { int len = underscoreString.length; if (len != 0) { - convertUnderscoresToCamelCaseOnInternal(underscoreString, capitalizeFirstLetter, len, sb); + convertUnderscoresToCamelCaseOn_(underscoreString, capitalizeFirstLetter, len, sb); } } - private static void convertUnderscoresToCamelCaseOnInternal(char[] underscoreString, boolean capitalizeFirstLetter, int len, StringBuffer sb) { + private static void convertUnderscoresToCamelCaseOn_(char[] underscoreString, boolean capitalizeFirstLetter, int len, StringBuffer sb) { char prev = 0; char c = 0; boolean first = true; @@ -2510,7 +3078,31 @@ public final class StringTools { } } - private static void convertUnderscoresToCamelCaseOnInternal(char[] underscoreString, boolean capitalizeFirstLetter, int len, StringBuilder sb) { + /** + * Convert the specified "underscore" string to a "camel case" string: + * "LARGE_PROJECT" -> "largeProject" + * Optionally capitalize the first letter. + */ + public static void convertUnderscoresToCamelCaseOn(String underscoreString, boolean capitalizeFirstLetter, StringBuilder sb) { + int len = underscoreString.length(); + if (len != 0) { + convertUnderscoresToCamelCaseOn_(underscoreString.toCharArray(), capitalizeFirstLetter, len, sb); + } + } + + /** + * Convert the specified "underscore" string to a "camel case" string: + * "LARGE_PROJECT" -> "largeProject" + * Optionally capitalize the first letter. + */ + public static void convertUnderscoresToCamelCaseOn(char[] underscoreString, boolean capitalizeFirstLetter, StringBuilder sb) { + int len = underscoreString.length; + if (len != 0) { + convertUnderscoresToCamelCaseOn_(underscoreString, capitalizeFirstLetter, len, sb); + } + } + + private static void convertUnderscoresToCamelCaseOn_(char[] underscoreString, boolean capitalizeFirstLetter, int len, StringBuilder sb) { char prev = 0; char c = 0; boolean first = true; @@ -2543,7 +3135,10 @@ public final class StringTools { * Optionally capitalize the first letter. */ public static void convertUnderscoresToCamelCaseOn(String underscoreString, boolean capitalizeFirstLetter, Writer writer) { - convertUnderscoresToCamelCaseOn(underscoreString.toCharArray(), capitalizeFirstLetter, writer); + int len = underscoreString.length(); + if (len != 0) { + convertUnderscoresToCamelCaseOn_(underscoreString.toCharArray(), capitalizeFirstLetter, len, writer); + } } /** @@ -2554,11 +3149,11 @@ public final class StringTools { public static void convertUnderscoresToCamelCaseOn(char[] underscoreString, boolean capitalizeFirstLetter, Writer writer) { int len = underscoreString.length; if (len != 0) { - convertUnderscoresToCamelCaseOnInternal(underscoreString, capitalizeFirstLetter, len, writer); + convertUnderscoresToCamelCaseOn_(underscoreString, capitalizeFirstLetter, len, writer); } } - private static void convertUnderscoresToCamelCaseOnInternal(char[] underscoreString, boolean capitalizeFirstLetter, int len, Writer writer) { + private static void convertUnderscoresToCamelCaseOn_(char[] underscoreString, boolean capitalizeFirstLetter, int len, Writer writer) { char prev = 0; char c = 0; boolean first = true; @@ -2602,9 +3197,6 @@ public final class StringTools { return result; } - - // ********** wrap Writer IOExceptions ********** - private static void writeStringOn(char[] string, Writer writer) { try { writer.write(string); @@ -2640,7 +3232,7 @@ public final class StringTools { // ********** constructor ********** - /** + /* * Suppress default constructor, ensuring non-instantiability. */ private StringTools() { diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedBoolean.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedBoolean.java index 059e31be0d..6fb05a9a33 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedBoolean.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedBoolean.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -140,11 +140,12 @@ public class SynchronizedBoolean /** * Suspend the current thread until the boolean value changes - * to the specified value. + * to the specified value. If the boolean value is already the + * specified value, return immediately. */ - public void waitUntilValueIs(boolean x) throws InterruptedException { + public void waitUntilValueIs(boolean v) throws InterruptedException { synchronized (this.mutex) { - while (this.value != x) { + while (this.value != v) { this.mutex.wait(); } } @@ -152,6 +153,7 @@ public class SynchronizedBoolean /** * Suspend the current thread until the boolean value changes to true. + * If the boolean value is already true, return immediately. */ public void waitUntilTrue() throws InterruptedException { synchronized (this.mutex) { @@ -161,6 +163,7 @@ public class SynchronizedBoolean /** * Suspend the current thread until the boolean value changes to false. + * If the boolean value is already false, return immediately. */ public void waitUntilFalse() throws InterruptedException { synchronized (this.mutex) { @@ -169,24 +172,38 @@ public class SynchronizedBoolean } /** + * Suspend the current thread until the boolean value changes to + * NOT the specified value, then change it back to the specified + * value and continue executing. If the boolean value is already + * NOT the specified value, set the value to the specified value + * immediately. + */ + public void waitToSetValue(boolean v) throws InterruptedException { + synchronized (this.mutex) { + this.waitUntilValueIs( ! v); + this.setValue(v); + } + } + + /** * Suspend the current thread until the boolean value changes to false, - * then change it back to true and continue executing. + * then change it back to true and continue executing. If the boolean + * value is already false, set the value to true immediately. */ public void waitToSetTrue() throws InterruptedException { synchronized (this.mutex) { - this.waitUntilFalse(); - this.setValue(true); + this.waitToSetValue(true); } } /** * Suspend the current thread until the boolean value changes to true, - * then change it back to false and continue executing. + * then change it back to false and continue executing. If the boolean + * value is already true, set the value to false immediately. */ public void waitToSetFalse() throws InterruptedException { synchronized (this.mutex) { - this.waitUntilTrue(); - this.setValue(false); + this.waitToSetValue(false); } } @@ -198,21 +215,23 @@ public class SynchronizedBoolean * to the specified value or the specified time-out occurs. * The time-out is specified in milliseconds. Return true if the specified * value was achieved; return false if a time-out occurred. + * If the boolean value is already the specified value, return true + * immediately. */ - public boolean waitUntilValueIs(boolean x, long timeout) throws InterruptedException { + public boolean waitUntilValueIs(boolean v, long timeout) throws InterruptedException { synchronized (this.mutex) { if (timeout == 0L) { - this.waitUntilValueIs(x); // wait indefinitely until notified + this.waitUntilValueIs(v); // wait indefinitely until notified return true; // if it ever comes back, the condition was met } long stop = System.currentTimeMillis() + timeout; long remaining = timeout; - while ((this.value != x) && (remaining > 0L)) { + while ((this.value != v) && (remaining > 0L)) { this.mutex.wait(remaining); remaining = stop - System.currentTimeMillis(); } - return (this.value == x); + return (this.value == v); } } @@ -221,6 +240,7 @@ public class SynchronizedBoolean * to true or the specified time-out occurs. * The time-out is specified in milliseconds. Return true if the specified * value was achieved; return false if a time-out occurred. + * If the boolean value is already true, return true immediately. */ public boolean waitUntilTrue(long timeout) throws InterruptedException { synchronized (this.mutex) { @@ -233,6 +253,7 @@ public class SynchronizedBoolean * to false or the specified time-out occurs. * The time-out is specified in milliseconds. Return true if the specified * value was achieved; return false if a time-out occurred. + * If the boolean value is already true, return true immediately. */ public boolean waitUntilFalse(long timeout) throws InterruptedException { synchronized (this.mutex) { @@ -241,38 +262,52 @@ public class SynchronizedBoolean } /** - * Suspend the current thread until the boolean value changes to false, - * then change it back to true and continue executing. If the boolean - * value does not change to false before the time-out, simply continue - * executing without changing the value. + * Suspend the current thread until the boolean value changes to NOT the + * specified value, then change it back to the specified value and continue + * executing. If the boolean value does not change to false before the + * time-out, simply continue executing without changing the value. * The time-out is specified in milliseconds. Return true if the value was - * set to true; return false if a time-out occurred. + * set to the specified value; return false if a time-out occurred. + * If the boolean value is already NOT the specified value, set the value + * to the specified value immediately and return true. */ - public boolean waitToSetTrue(long timeout) throws InterruptedException { + public boolean waitToSetValue(boolean v, long timeout) throws InterruptedException { synchronized (this.mutex) { - boolean success = this.waitUntilFalse(timeout); + boolean success = this.waitUntilValueIs( ! v, timeout); if (success) { - this.setValue(true); + this.setValue(v); } return success; } } /** + * Suspend the current thread until the boolean value changes to false, + * then change it back to true and continue executing. If the boolean + * value does not change to false before the time-out, simply continue + * executing without changing the value. The time-out is specified in + * milliseconds. Return true if the value was set to true; return false + * if a time-out occurred. If the boolean value is already false, set the + * value to true immediately and return true. + */ + public boolean waitToSetTrue(long timeout) throws InterruptedException { + synchronized (this.mutex) { + return this.waitToSetValue(true, timeout); + } + } + + /** * Suspend the current thread until the boolean value changes to true, * then change it back to false and continue executing. If the boolean * value does not change to true before the time-out, simply continue - * executing without changing the value. - * The time-out is specified in milliseconds. Return true if the value was - * set to false; return false if a time-out occurred. + * executing without changing the value. The time-out is specified in + * milliseconds. Return true if the value was set to false; return false + * if a time-out occurred. If the boolean value is already true, set the + * value to false immediately and return true. */ public boolean waitToSetFalse(long timeout) throws InterruptedException { synchronized (this.mutex) { - boolean success = this.waitUntilTrue(timeout); - if (success) { - this.setValue(false); - } - return success; + return this.waitToSetValue(false, timeout); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedObject.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedObject.java index cada106e04..b71421bb0f 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedObject.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedObject.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -122,11 +122,12 @@ public class SynchronizedObject<T> /** * Suspend the current thread until the value changes - * to the specified value. + * to the specified value. If the value is already the + * specified value, return immediately. */ - public void waitUntilValueIs(T x) throws InterruptedException { + public void waitUntilValueIs(T v) throws InterruptedException { synchronized (this.mutex) { - while (this.value != x) { + while (this.value != v) { this.mutex.wait(); } } @@ -134,11 +135,12 @@ public class SynchronizedObject<T> /** * Suspend the current thread until the value changes - * to something other than the specified value. + * to something other than the specified value. If the + * value is already NOT the specified value, return immediately. */ - public void waitUntilValueIsNot(T x) throws InterruptedException { + public void waitUntilValueIsNot(T v) throws InterruptedException { synchronized (this.mutex) { - while (this.value == x) { + while (this.value == v) { this.mutex.wait(); } } @@ -146,6 +148,7 @@ public class SynchronizedObject<T> /** * Suspend the current thread until the value changes to null. + * If the value is already null, return immediately. */ public void waitUntilNull() throws InterruptedException { synchronized (this.mutex) { @@ -156,6 +159,7 @@ public class SynchronizedObject<T> /** * Suspend the current thread until the value changes * to something other than null. + * If the value is already NOT null, return immediately. */ public void waitUntilNotNull() throws InterruptedException { synchronized (this.mutex) { @@ -167,17 +171,21 @@ public class SynchronizedObject<T> * Suspend the current thread until the value changes to * something other than the specified value, then change * it back to the specified value and continue executing. + * If the value is already NOT the specified value, set + * the value immediately. */ - public void waitToSetValue(T x) throws InterruptedException { + public void waitToSetValue(T v) throws InterruptedException { synchronized (this.mutex) { - this.waitUntilValueIsNot(x); - this.setValue(x); + this.waitUntilValueIsNot(v); + this.setValue(v); } } /** * Suspend the current thread until the value changes to - * null, then change it back to null and continue executing. + * something other than null, then change it back to null + * and continue executing. If the value is already NOT null, + * set the value to null immediately. */ public void waitToSetNull() throws InterruptedException { synchronized (this.mutex) { @@ -194,21 +202,22 @@ public class SynchronizedObject<T> * to the specified value or the specified time-out occurs. * The time-out is specified in milliseconds. Return true if the specified * value was achieved; return false if a time-out occurred. + * If the value is already the specified value, return true immediately. */ - public boolean waitUntilValueIs(T x, long timeout) throws InterruptedException { + public boolean waitUntilValueIs(T v, long timeout) throws InterruptedException { synchronized (this.mutex) { if (timeout == 0L) { - this.waitUntilValueIs(x); // wait indefinitely until notified + this.waitUntilValueIs(v); // wait indefinitely until notified return true; // if it ever comes back, the condition was met } long stop = System.currentTimeMillis() + timeout; long remaining = timeout; - while ((this.value != x) && (remaining > 0L)) { + while ((this.value != v) && (remaining > 0L)) { this.mutex.wait(remaining); remaining = stop - System.currentTimeMillis(); } - return (this.value == x); + return (this.value == v); } } @@ -217,21 +226,22 @@ public class SynchronizedObject<T> * other than the specified value or the specified time-out occurs. * The time-out is specified in milliseconds. Return true if the specified * value was removed; return false if a time-out occurred. + * If the value is already NOT the specified value, return true immediately. */ - public boolean waitUntilValueIsNot(T x, long timeout) throws InterruptedException { + public boolean waitUntilValueIsNot(T v, long timeout) throws InterruptedException { synchronized (this.mutex) { if (timeout == 0L) { - this.waitUntilValueIsNot(x); // wait indefinitely until notified + this.waitUntilValueIsNot(v); // wait indefinitely until notified return true; // if it ever comes back, the condition was met } long stop = System.currentTimeMillis() + timeout; long remaining = timeout; - while ((this.value == x) && (remaining > 0L)) { + while ((this.value == v) && (remaining > 0L)) { this.mutex.wait(remaining); remaining = stop - System.currentTimeMillis(); } - return (this.value != x); + return (this.value != v); } } @@ -240,6 +250,7 @@ public class SynchronizedObject<T> * to null or the specified time-out occurs. * The time-out is specified in milliseconds. Return true if the specified * value was achieved; return false if a time-out occurred. + * If the value is already null, return true immediately. */ public boolean waitUntilNull(long timeout) throws InterruptedException { synchronized (this.mutex) { @@ -252,6 +263,7 @@ public class SynchronizedObject<T> * to something other than null or the specified time-out occurs. * The time-out is specified in milliseconds. Return true if the specified * value was achieved; return false if a time-out occurred. + * If the value is already NOT null, return true immediately. */ public boolean waitUntilNotNull(long timeout) throws InterruptedException { synchronized (this.mutex) { @@ -268,12 +280,14 @@ public class SynchronizedObject<T> * without changing the value. * The time-out is specified in milliseconds. Return true if the value was * set to true; return false if a time-out occurred. + * If the value is already something other than the specified value, set + * the value immediately and return true. */ - public boolean waitToSetValue(T x, long timeout) throws InterruptedException { + public boolean waitToSetValue(T v, long timeout) throws InterruptedException { synchronized (this.mutex) { - boolean success = this.waitUntilValueIsNot(x, timeout); + boolean success = this.waitUntilValueIsNot(v, timeout); if (success) { - this.setValue(x); + this.setValue(v); } return success; } @@ -286,6 +300,8 @@ public class SynchronizedObject<T> * the time-out, simply continue executing without changing the value. * The time-out is specified in milliseconds. Return true if the value was * set to false; return false if a time-out occurred. + * If the value is already something other than null, set + * the value to null immediately and return true. */ public boolean waitToSetNull(long timeout) throws InterruptedException { synchronized (this.mutex) { @@ -335,16 +351,16 @@ public class SynchronizedObject<T> if ( ! (obj instanceof SynchronizedObject)) { return false; } - Object thisValue = this.value(); - Object otherValue = ((SynchronizedObject<?>) obj).value(); - return (thisValue == null) ? - (otherValue == null) : thisValue.equals(otherValue); + Object v1 = this.value(); + Object v2 = ((SynchronizedObject<?>) obj).value(); + return (v1 == null) ? + (v2 == null) : v1.equals(v2); } @Override public int hashCode() { - Object temp = this.value(); - return (temp == null) ? 0 : temp.hashCode(); + Object v = this.value(); + return (v == null) ? 0 : v.hashCode(); } @Override diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java index 6455e84257..8f4fb89ab5 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -261,7 +261,7 @@ public class SynchronizedStack<E> * Return the object this object locks on while performing * its operations. */ - public Object getMutex() { + public Object mutex() { return this.mutex; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java index e238d4b3c0..cf823a5e2d 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -32,7 +32,7 @@ import org.eclipse.jpt.utility.internal.StringTools; public class CloneIterator<E> implements Iterator<E> { - private final Iterator<E> nestedIterator; + private final Iterator<Object> nestedIterator; private E current; private final Mutator<E> mutator; private boolean removeAllowed; @@ -56,17 +56,12 @@ public class CloneIterator<E> */ public CloneIterator(Collection<? extends E> c, Mutator<E> mutator) { super(); - this.nestedIterator = new ArrayIterator<E>(buildArray(c)); + this.nestedIterator = new ArrayIterator<Object>(c.toArray()); this.current = null; this.mutator = mutator; this.removeAllowed = false; } - @SuppressWarnings("unchecked") - private static <T> T[] buildArray(Collection<? extends T> c) { - return (T[]) c.toArray(); - } - // ********** Iterator implementation ********** @@ -75,7 +70,7 @@ public class CloneIterator<E> } public E next() { - this.current = this.nestedIterator.next(); + this.current = this.nestedNext(); this.removeAllowed = true; return this.current; } @@ -92,6 +87,17 @@ public class CloneIterator<E> // ********** internal methods ********** /** + * The collection passed in during construction held Es, + * so this cast is not a problem. We need this cast because + * all the elements of the original collection were copied into + * an object array (Object[]). + */ + @SuppressWarnings("unchecked") + protected E nestedNext() { + return (E) this.nestedIterator.next(); + } + + /** * Remove the specified element from the original collection. * <p> * This method can be overridden by a subclass as an diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneListIterator.java index e3606402bb..bbad3409e2 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneListIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneListIterator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,7 +9,6 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.iterators; -import java.util.Collection; import java.util.List; import java.util.ListIterator; @@ -34,7 +33,7 @@ import org.eclipse.jpt.utility.internal.StringTools; public class CloneListIterator<E> implements ListIterator<E> { - private final ListIterator<E> nestedListIterator; + private final ListIterator<Object> nestedListIterator; private int cursor; private String state; private final Mutator<E> mutator; @@ -63,17 +62,12 @@ public class CloneListIterator<E> super(); // build a copy of the list and keep it in synch with original (if the mutator allows changes) // that way the nested list iterator will maintain some of our state - this.nestedListIterator = CollectionTools.list(buildArray(list)).listIterator(); + this.nestedListIterator = CollectionTools.list(list.toArray()).listIterator(); this.mutator = mutator; this.cursor = 0; this.state = UNKNOWN; } - @SuppressWarnings("unchecked") - private static <T> T[] buildArray(Collection<? extends T> c) { - return (T[]) c.toArray(); - } - // ********** ListIterator implementation ********** @@ -83,7 +77,7 @@ public class CloneListIterator<E> public E next() { // allow the nested iterator to throw an exception before we modify the index - E next = this.nestedListIterator.next(); + E next = this.nestedNext(); this.cursor++; this.state = NEXT; return next; @@ -114,7 +108,7 @@ public class CloneListIterator<E> public E previous() { // allow the nested iterator to throw an exception before we modify the index - E previous = this.nestedListIterator.previous(); + E previous = this.nestedPrevious(); this.cursor--; this.state = PREVIOUS; return previous; @@ -141,6 +135,28 @@ public class CloneListIterator<E> // ********** internal methods ********** /** + * The list passed in during construction held Es, + * so this cast is not a problem. We need this cast because + * all the elements of the original collection were copied into + * an object array (Object[]). + */ + @SuppressWarnings("unchecked") + protected E nestedNext() { + return (E) this.nestedListIterator.next(); + } + + /** + * The list passed in during construction held Es, + * so this cast is not a problem. We need this cast because + * all the elements of the original collection were copied into + * an object array (Object[]). + */ + @SuppressWarnings("unchecked") + protected E nestedPrevious() { + return (E) this.nestedListIterator.previous(); + } + + /** * Add the specified element to the original list. * <p> * This method can be overridden by a subclass as an diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeListIterator.java index 324d3c2f68..c2037f053d 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeListIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeListIterator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -39,7 +39,7 @@ public class CompositeListIterator<E> public CompositeListIterator(List<? extends ListIterator<E>> iterators) { this(iterators.listIterator()); } - + /** * Construct a list iterator with the specified list of list iterators. */ @@ -49,7 +49,7 @@ public class CompositeListIterator<E> this.nextIndex = 0; this.nextReturned = false; } - + /** * Construct a list iterator with the specified object prepended * to the specified iterator. @@ -58,7 +58,7 @@ public class CompositeListIterator<E> public CompositeListIterator(E object, ListIterator<E> iterator) { this(new SingleElementListIterator<E>(object), iterator); } - + /** * Construct a list iterator with the specified object appended * to the specified iterator. @@ -67,7 +67,7 @@ public class CompositeListIterator<E> public CompositeListIterator(ListIterator<E> iterator, E object) { this(iterator, new SingleElementListIterator<E>(object)); } - + /** * Construct a list iterator with the specified list iterators. */ @@ -80,7 +80,7 @@ public class CompositeListIterator<E> this.nextIterator.add(o); this.nextIndex++; } - + public boolean hasNext() { try { this.loadNextIterator(); @@ -90,7 +90,7 @@ public class CompositeListIterator<E> } return this.nextIterator.hasNext(); } - + public boolean hasPrevious() { try { this.loadPreviousIterator(); @@ -100,43 +100,43 @@ public class CompositeListIterator<E> } return this.nextIterator.hasPrevious(); } - + public E next() { this.loadNextIterator(); E result = this.nextIterator.next(); - + // the statement above will throw a NoSuchElementException // if the current iterator is at the end of the line; - // so if we get here, we can set the lastIteratorToReturnElement + // so if we get here, we can set the 'lastIteratorToReturnElement' this.lastIteratorToReturnElement = this.nextIterator; this.nextIndex++; this.nextReturned = true; - + return result; } - + public int nextIndex() { return this.nextIndex; } - + public E previous() { this.loadPreviousIterator(); E result = this.nextIterator.previous(); - + // the statement above will throw a NoSuchElementException // if the current iterator is at the end of the line; - // so if we get here, we can set the lastIteratorToReturnElement + // so if we get here, we can set the 'lastIteratorToReturnElement' this.lastIteratorToReturnElement = this.nextIterator; this.nextIndex--; this.nextReturned = false; - + return result; } - + public int previousIndex() { return this.nextIndex - 1; } - + public void remove() { if (this.lastIteratorToReturnElement == null) { throw new IllegalStateException(); @@ -147,16 +147,16 @@ public class CompositeListIterator<E> this.nextIndex--; } } - + public void set(E e) { if (this.lastIteratorToReturnElement == null) { throw new IllegalStateException(); } this.lastIteratorToReturnElement.set(e); } - + /** - * Load nextIterator with the first iterator that <code>hasNext()</code> + * Load 'nextIterator' with the first iterator that <code>hasNext()</code> * or the final iterator if all the elements have already been retrieved. */ private void loadNextIterator() { @@ -165,9 +165,9 @@ public class CompositeListIterator<E> this.nextIterator = this.iterators.next(); } } - + /** - * Load nextIterator with the first iterator that <code>hasPrevious()</code> + * Load 'nextIterator' with the first iterator that <code>hasPrevious()</code> * or the first iterator if all the elements have already been retrieved. */ private void loadPreviousIterator() { @@ -176,19 +176,19 @@ public class CompositeListIterator<E> this.nextIterator = this.iterators.previous(); } } - + /** - * If nextIterator is null, load it with the first iterator. + * If 'nextIterator' is null, load it with the first iterator. */ private void checkNextIterator() { if (this.nextIterator == null) { this.nextIterator = this.iterators.next(); } } - + @Override public String toString() { return StringTools.buildToStringFor(this, this.iterators); } - + } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyIterator.java index cb85a24c51..af8a394119 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyIterator.java @@ -14,7 +14,7 @@ import java.util.NoSuchElementException; import org.eclipse.jpt.utility.internal.StringTools; /** - * A <code>NullIterator</code> is just that. + * An <code>EmptyIterator</code> is just that. */ public final class EmptyIterator<E> implements Iterator<E> diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyListIterator.java index ba93e81790..70a3367377 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyListIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyListIterator.java @@ -15,7 +15,7 @@ import java.util.NoSuchElementException; import org.eclipse.jpt.utility.internal.StringTools; /** - * A <code>NullListIterator</code> is just that. + * An <code>EmptyListIterator</code> is just that. */ public final class EmptyListIterator<E> implements ListIterator<E> diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/FilteringIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/FilteringIterator.java index 02de67b77c..e11559c39c 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/FilteringIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/FilteringIterator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -33,14 +33,12 @@ import org.eclipse.jpt.utility.internal.StringTools; * This also prevents a filtered iterator from supporting the optional * <code>remove()</code> method. */ -public class FilteringIterator<E> - implements Iterator<E> +public class FilteringIterator<E1, E2> + implements Iterator<E2> { - private final Iterator<?> nestedIterator; - // trust that the filter is correct - i.e. it will only accept elements of type E - @SuppressWarnings("unchecked") - private final Filter filter; - private E next; + private final Iterator<? extends E1> nestedIterator; + private final Filter<E1> filter; + private E2 next; private boolean done; @@ -51,15 +49,15 @@ public class FilteringIterator<E> * <code>accept(Object)</code> method instead of building * a <code>Filter</code>. */ - public FilteringIterator(Iterator<?> nestedIterator) { - this(nestedIterator, Filter.Disabled.instance()); + public FilteringIterator(Iterator<? extends E1> nestedIterator) { + this(nestedIterator, Filter.Disabled.<E1>instance()); } /** * Construct an iterator with the specified nested * iterator and filter. */ - public FilteringIterator(Iterator<?> nestedIterator, @SuppressWarnings("unchecked") Filter filter) { + public FilteringIterator(Iterator<? extends E1> nestedIterator, Filter<E1> filter) { super(); this.nestedIterator = nestedIterator; this.filter = filter; @@ -70,11 +68,11 @@ public class FilteringIterator<E> return ! this.done; } - public E next() { + public E2 next() { if (this.done) { throw new NoSuchElementException(); } - E result = this.next; + E2 result = this.next; this.loadNext(); return result; } @@ -95,10 +93,10 @@ public class FilteringIterator<E> private void loadNext() { this.done = true; while (this.nestedIterator.hasNext() && (this.done)) { - Object o = this.nestedIterator.next(); - if (this.accept(o)) { + E1 temp = this.nestedIterator.next(); + if (this.accept(temp)) { // assume that if the object was accepted it is of type E - this.next = this.downcast(o); + this.next = this.cast(temp); this.done = false; } else { this.next = null; @@ -107,9 +105,13 @@ public class FilteringIterator<E> } } + /** + * We have to assume the filter will only "accept" objects that can + * be cast to E2. + */ @SuppressWarnings("unchecked") - private E downcast(Object o) { - return (E) o; + private E2 cast(E1 o) { + return (E2) o; } /** @@ -120,8 +122,7 @@ public class FilteringIterator<E> * This method can be overridden by a subclass as an * alternative to building a <code>Filter</code>. */ - @SuppressWarnings("unchecked") - protected boolean accept(Object o) { + protected boolean accept(E1 o) { return this.filter.accept(o); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyCompositeListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyCompositeListIterator.java new file mode 100644 index 0000000000..d13d36e25b --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyCompositeListIterator.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.iterators; + +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.eclipse.jpt.utility.internal.StringTools; + +/** + * A <code>ReadOnlyCompositeListIterator</code> wraps a list + * of <code>ListIterator</code>s and makes them appear to be a single + * read-only <code>ListIterator</code>. A read-only composite list + * iterator is more flexible than a normal composite when it comes to the element types of + * the nested iterators. + */ +public class ReadOnlyCompositeListIterator<E> + implements ListIterator<E> +{ + private final ListIterator<? extends ListIterator<? extends E>> iterators; + private ListIterator<? extends E> nextIterator; + private int nextIndex; + + + /** + * Construct a read-only list iterator with the specified list of + * list iterators. + */ + public ReadOnlyCompositeListIterator(List<? extends ListIterator<? extends E>> iterators) { + this(iterators.listIterator()); + } + + /** + * Construct a read-only list iterator with the specified list of + * list iterators. + */ + public ReadOnlyCompositeListIterator(ListIterator<? extends ListIterator<? extends E>> iterators) { + super(); + this.iterators = iterators; + this.nextIndex = 0; + } + + /** + * Construct a read-only list iterator with the specified object prepended + * to the specified iterator. + */ + @SuppressWarnings("unchecked") + public ReadOnlyCompositeListIterator(E object, ListIterator<? extends E> iterator) { + this(new SingleElementListIterator<E>(object), iterator); + } + + /** + * Construct a read-only list iterator with the specified object appended + * to the specified iterator. + */ + @SuppressWarnings("unchecked") + public ReadOnlyCompositeListIterator(ListIterator<? extends E> iterator, E object) { + this(iterator, new SingleElementListIterator<E>(object)); + } + + /** + * Construct a read-only list iterator with the specified list iterators. + */ + public ReadOnlyCompositeListIterator(ListIterator<? extends E>... iterators) { + this(new ArrayListIterator<ListIterator<? extends E>>(iterators)); + } + + public boolean hasNext() { + try { + this.loadNextIterator(); + } catch (NoSuchElementException ex) { + // this occurs if there are no iterators at all + return false; + } + return this.nextIterator.hasNext(); + } + + public boolean hasPrevious() { + try { + this.loadPreviousIterator(); + } catch (NoSuchElementException ex) { + // this occurs if there are no iterators at all + return false; + } + return this.nextIterator.hasPrevious(); + } + + public E next() { + this.loadNextIterator(); + E result = this.nextIterator.next(); + + // the statement above will throw a NoSuchElementException + // if the current iterator is at the end of the line; + // so if we get here, we can increment 'nextIndex' + this.nextIndex++; + + return result; + } + + public int nextIndex() { + return this.nextIndex; + } + + public E previous() { + this.loadPreviousIterator(); + E result = this.nextIterator.previous(); + + // the statement above will throw a NoSuchElementException + // if the current iterator is at the end of the line; + // so if we get here, we can decrement 'nextIndex' + this.nextIndex--; + + return result; + } + + public int previousIndex() { + return this.nextIndex - 1; + } + + public void add(E o) { + // the list iterator is read-only + throw new UnsupportedOperationException(); + } + + public void remove() { + // the list iterator is read-only + throw new UnsupportedOperationException(); + } + + public void set(E e) { + // the list iterator is read-only + throw new UnsupportedOperationException(); + } + + /** + * Load nextIterator with the first iterator that <code>hasNext()</code> + * or the final iterator if all the elements have already been retrieved. + */ + private void loadNextIterator() { + this.checkNextIterator(); + while (( ! this.nextIterator.hasNext()) && this.iterators.hasNext()) { + this.nextIterator = this.iterators.next(); + } + } + + /** + * Load nextIterator with the first iterator that <code>hasPrevious()</code> + * or the first iterator if all the elements have already been retrieved. + */ + private void loadPreviousIterator() { + this.checkNextIterator(); + while (( ! this.nextIterator.hasPrevious()) && this.iterators.hasPrevious()) { + this.nextIterator = this.iterators.previous(); + } + } + + /** + * If 'nextIterator' is null, load it with the first iterator. + */ + private void checkNextIterator() { + if (this.nextIterator == null) { + this.nextIterator = this.iterators.next(); + } + } + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.iterators); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/AbstractModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/AbstractModel.java index 0c7b5da6d8..a0481df157 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/AbstractModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/AbstractModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -11,6 +11,7 @@ package org.eclipse.jpt.utility.internal.model; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -18,6 +19,7 @@ import java.util.List; import org.eclipse.jpt.utility.internal.CollectionTools; import org.eclipse.jpt.utility.internal.HashBag; import org.eclipse.jpt.utility.internal.StringTools; +import org.eclipse.jpt.utility.internal.iterators.ArrayIterator; import org.eclipse.jpt.utility.internal.model.event.CollectionChangeEvent; import org.eclipse.jpt.utility.internal.model.event.ListChangeEvent; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; @@ -211,6 +213,17 @@ public abstract class AbstractModel implements Model, Serializable { * Return whether collection changed. * @see java.util.Collection#addAll(java.util.Collection) */ + protected <E> boolean addItemsToCollection(E[] items, Collection<E> collection, String collectionName) { + return this.addItemsToCollection(new ArrayIterator<E>(items), collection, collectionName); + } + + /** + * Convenience method. + * Add the specified items to the specified bound collection + * and fire the appropriate event if necessary. + * Return whether collection changed. + * @see java.util.Collection#addAll(java.util.Collection) + */ protected <E> boolean addItemsToCollection(Iterable<? extends E> items, Collection<E> collection, String collectionName) { return this.addItemsToCollection(items.iterator(), collection, collectionName); } @@ -262,6 +275,17 @@ public abstract class AbstractModel implements Model, Serializable { * Return whether the collection changed. * @see java.util.Collection#removeAll(java.util.Collection) */ + protected boolean removeItemsFromCollection(Object[] items, Collection<?> collection, String collectionName) { + return this.removeItemsFromCollection(new ArrayIterator<Object>(items), collection, collectionName); + } + + /** + * Convenience method. + * Remove the specified items from the specified bound collection + * and fire the appropriate event if necessary. + * Return whether the collection changed. + * @see java.util.Collection#removeAll(java.util.Collection) + */ protected boolean removeItemsFromCollection(Iterable<?> items, Collection<?> collection, String collectionName) { return this.removeItemsFromCollection(items.iterator(), collection, collectionName); } @@ -291,6 +315,17 @@ public abstract class AbstractModel implements Model, Serializable { * Return whether the collection changed. * @see java.util.Collection#retainAll(java.util.Collection) */ + protected boolean retainItemsInCollection(Object[] items, Collection<?> collection, String collectionName) { + return this.retainItemsInCollection(new ArrayIterator<Object>(items), collection, collectionName); + } + + /** + * Convenience method. + * Retain the specified items in the specified bound collection + * and fire the appropriate event if necessary. + * Return whether the collection changed. + * @see java.util.Collection#retainAll(java.util.Collection) + */ protected boolean retainItemsInCollection(Iterable<?> items, Collection<?> collection, String collectionName) { return this.retainItemsInCollection(items.iterator(), collection, collectionName); } @@ -482,6 +517,16 @@ public abstract class AbstractModel implements Model, Serializable { * and fire the appropriate event if necessary. * @see java.util.List#addAll(int, java.util.Collection) */ + protected <E> boolean addItemsToList(int index, E[] items, List<E> list, String listName) { + return this.addItemsToList(index, new ArrayIterator<E>(items), list, listName); + } + + /** + * Convenience method. + * Add the specified items to the specified bound list + * and fire the appropriate event if necessary. + * @see java.util.List#addAll(int, java.util.Collection) + */ protected <E> boolean addItemsToList(int index, Iterable<? extends E> items, List<E> list, String listName) { return this.addItemsToList(index, items.iterator(), list, listName); } @@ -507,6 +552,16 @@ public abstract class AbstractModel implements Model, Serializable { * and fire the appropriate event if necessary. * @see java.util.List#addAll(java.util.Collection) */ + protected <E> boolean addItemsToList(E[] items, List<E> list, String listName) { + return this.addItemsToList(new ArrayIterator<E>(items), list, listName); + } + + /** + * Convenience method. + * Add the specified items to the end of to the specified bound list + * and fire the appropriate event if necessary. + * @see java.util.List#addAll(java.util.Collection) + */ protected <E> boolean addItemsToList(Iterable<? extends E> items, List<E> list, String listName) { return this.addItemsToList(items.iterator(), list, listName); } @@ -579,6 +634,17 @@ public abstract class AbstractModel implements Model, Serializable { * Return the removed items. * @see java.util.List#removeAll(java.util.Collection) */ + protected boolean removeItemsFromList(Object[] items, List<?> list, String listName) { + return this.removeItemsFromList(new ArrayIterator<Object>(items), list, listName); + } + + /** + * Convenience method. + * Remove the specified items from the specified bound list + * and fire the appropriate event if necessary. + * Return the removed items. + * @see java.util.List#removeAll(java.util.Collection) + */ protected boolean removeItemsFromList(Iterable<?> items, List<?> list, String listName) { return this.removeItemsFromList(items.iterator(), list, listName); } @@ -605,6 +671,17 @@ public abstract class AbstractModel implements Model, Serializable { * Return whether the collection changed. * @see java.util.List#retainAll(java.util.Collection) */ + protected boolean retainItemsInList(Object[] items, List<?> list, String listName) { + return this.retainItemsInList(new ArrayIterator<Object>(items), list, listName); + } + + /** + * Convenience method. + * Retain the specified items in the specified bound list + * and fire the appropriate event if necessary. + * Return whether the collection changed. + * @see java.util.List#retainAll(java.util.Collection) + */ protected boolean retainItemsInList(Iterable<?> items, List<?> list, String listName) { return this.retainItemsInList(items.iterator(), list, listName); } @@ -654,6 +731,17 @@ public abstract class AbstractModel implements Model, Serializable { * Return the replaced items. * @see java.util.List#set(int, Object) */ + protected <E> List<E> setItemsInList(int index, E[] items, List<E> list, String listName) { + return this.setItemsInList(index, Arrays.asList(items), list, listName); + } + + /** + * Convenience method. + * Set the specified items in the specified bound list + * and fire the appropriate event if necessary. + * Return the replaced items. + * @see java.util.List#set(int, Object) + */ protected <E> List<E> setItemsInList(int index, List<? extends E> items, List<E> list, String listName) { List<E> subList = list.subList(index, index + items.size()); List<E> replacedItems = new ArrayList<E>(subList); diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/CollectionChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/CollectionChangeEvent.java index af7671638e..dee500c269 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/CollectionChangeEvent.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/CollectionChangeEvent.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -72,7 +72,6 @@ public class CollectionChangeEvent extends ChangeEvent { * @param source The object on which the event initially occurred. * @param collectionName The programmatic name of the collection that was changed. */ - @SuppressWarnings("unchecked") public CollectionChangeEvent(Model source, String collectionName) { this(source, collectionName, Collections.emptySet()); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/ListChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/ListChangeEvent.java index c2512e2f62..e01f183dcc 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/ListChangeEvent.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/ListChangeEvent.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -117,7 +117,6 @@ public class ListChangeEvent extends ChangeEvent { * @param index The index at which the items were added to or removed from the list. * @param items The items that were added to or removed from the list. */ - @SuppressWarnings("unchecked") public ListChangeEvent(Model source, String listName, int index, List<?> items) { this(source, listName, index, items, Collections.emptyList(), -1, -1); } @@ -130,7 +129,6 @@ public class ListChangeEvent extends ChangeEvent { * @param targetIndex The index to which the items were moved. * @param sourceIndex The index from which the items were moved. */ - @SuppressWarnings("unchecked") public ListChangeEvent(Model source, String listName, int targetIndex, int sourceIndex, int length) { this(source, listName, targetIndex, Collections.emptyList(), Collections.emptyList(), sourceIndex, length); } @@ -141,7 +139,6 @@ public class ListChangeEvent extends ChangeEvent { * @param source The object on which the event initially occurred. * @param listName The programmatic name of the list that was changed. */ - @SuppressWarnings("unchecked") public ListChangeEvent(Model source, String listName) { this(source, listName, -1, Collections.emptyList(), Collections.emptyList(), -1, -1); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/TreeChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/TreeChangeEvent.java index 47b73a9d7c..c5b99893b1 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/TreeChangeEvent.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/event/TreeChangeEvent.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -59,7 +59,6 @@ public class TreeChangeEvent extends ChangeEvent { * @param source The object on which the event initially occurred. * @param treeName The programmatic name of the tree that was changed. */ - @SuppressWarnings("unchecked") public TreeChangeEvent(Model source, String treeName) { this(source, treeName, EMPTY_PATH); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AbstractTreeNodeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AbstractTreeNodeValueModel.java index d327fc5c14..a076466396 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AbstractTreeNodeValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AbstractTreeNodeValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -41,9 +41,9 @@ import org.eclipse.jpt.utility.internal.model.listener.StateChangeListener; * override these methods to listen to the node's value if * it can change in a way that should be reflected in the tree */ -public abstract class AbstractTreeNodeValueModel +public abstract class AbstractTreeNodeValueModel<T> extends AbstractModel - implements TreeNodeValueModel + implements TreeNodeValueModel<T> { @@ -58,14 +58,18 @@ public abstract class AbstractTreeNodeValueModel @Override protected ChangeSupport buildChangeSupport() { - // this value model is allowed to fire state change events... -// return new ValueModelChangeSupport(this); + // this model fires *both* "value property change" and "state change" events... +// return new SingleAspectChangeSupport(this, PropertyChangeListener.class, PropertyValueModel.VALUE); return super.buildChangeSupport(); } // ********** extend AbstractModel implementation ********** + /** + * Clients should be adding both "state change" and "value property change" + * listeners. + */ @Override public void addStateChangeListener(StateChangeListener listener) { if (this.hasNoStateChangeListeners()) { @@ -75,13 +79,14 @@ public abstract class AbstractTreeNodeValueModel } /** - * Begin listening to the node's value. If the state of the node changes + * Begin listening to the node's value's state. If the state of the node changes * in a way that should be reflected in the tree, fire a "state change" event. - * If the entire value of the node changes, fire a "value property change" - * event. */ protected abstract void engageValue(); + /** + * @see #addStateChangeListener(StateChangeListener) + */ @Override public void removeStateChangeListener(StateChangeListener listener) { super.removeStateChangeListener(listener); @@ -97,17 +102,18 @@ public abstract class AbstractTreeNodeValueModel protected abstract void disengageValue(); - // ********** PropertyValueModel implementation ********** + // ********** WritablePropertyValueModel implementation ********** - public void setValue(Object value) { + public void setValue(T value) { throw new UnsupportedOperationException(); } // ********** TreeNodeValueModel implementation ********** - public TreeNodeValueModel[] path() { - List<TreeNodeValueModel> path = CollectionTools.reverseList(this.backPath()); + @SuppressWarnings("unchecked") + public TreeNodeValueModel<T>[] path() { + List<TreeNodeValueModel<T>> path = CollectionTools.reverseList(this.backPath()); return path.toArray(new TreeNodeValueModel[path.size()]); } @@ -116,25 +122,25 @@ public abstract class AbstractTreeNodeValueModel * starting with, and including, the node * and up to, and including, the root node. */ - protected Iterator<TreeNodeValueModel> backPath() { - return new ChainIterator<TreeNodeValueModel>(this) { + protected Iterator<TreeNodeValueModel<T>> backPath() { + return new ChainIterator<TreeNodeValueModel<T>>(this) { @Override - protected TreeNodeValueModel nextLink(TreeNodeValueModel currentLink) { + protected TreeNodeValueModel<T> nextLink(TreeNodeValueModel<T> currentLink) { return currentLink.parent(); } }; } - public TreeNodeValueModel child(int index) { - return (TreeNodeValueModel) this.childrenModel().get(index); + public TreeNodeValueModel<T> child(int index) { + return this.childrenModel().get(index); } public int childrenSize() { return this.childrenModel().size(); } - public int indexOfChild(TreeNodeValueModel child) { - ListValueModel children = this.childrenModel(); + public int indexOfChild(TreeNodeValueModel<T> child) { + ListValueModel<TreeNodeValueModel<T>> children = this.childrenModel(); int size = children.size(); for (int i = 0; i < size; i++) { if (children.get(i) == child) { @@ -169,7 +175,8 @@ public abstract class AbstractTreeNodeValueModel if (o.getClass() != this.getClass()) { return false; } - AbstractTreeNodeValueModel other = (AbstractTreeNodeValueModel) o; + @SuppressWarnings("unchecked") + AbstractTreeNodeValueModel<T> other = (AbstractTreeNodeValueModel<T>) o; return this.value().equals(other.value()); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectAdapter.java index 93e60d517f..556ae2bea5 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -26,7 +26,7 @@ import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; * adapter itself actually has listeners. This will allow the adapter to be * garbage collected when appropriate */ -public abstract class AspectAdapter +public abstract class AspectAdapter<S> extends AbstractModel { /** @@ -35,7 +35,7 @@ public abstract class AspectAdapter * We need to hold on to this directly so we can * disengage it when it changes. */ - protected Object subject; + protected S subject; /** * A value model that holds the subject @@ -46,7 +46,7 @@ public abstract class AspectAdapter * For now, this is can only be set upon construction and is * immutable. */ - protected final ValueModel subjectHolder; + protected final PropertyValueModel<? extends S> subjectHolder; /** A listener that keeps us in synch with the subjectHolder. */ protected final PropertyChangeListener subjectChangeListener; @@ -57,15 +57,15 @@ public abstract class AspectAdapter /** * Construct an AspectAdapter for the specified subject. */ - protected AspectAdapter(Object subject) { - this(new ReadOnlyPropertyValueModel(subject)); + protected AspectAdapter(S subject) { + this(new StaticPropertyValueModel<S>(subject)); } /** * Construct an AspectAdapter for the specified subject holder. * The subject holder cannot be null. */ - protected AspectAdapter(ValueModel subjectHolder) { + protected AspectAdapter(PropertyValueModel<? extends S> subjectHolder) { super(); if (subjectHolder == null) { throw new NullPointerException(); @@ -154,39 +154,39 @@ public abstract class AspectAdapter */ protected abstract void fireAspectChange(Object oldValue, Object newValue); - /** - * The subject is not null - add our listener. - */ - protected abstract void engageNonNullSubject(); - protected void engageSubject() { // check for nothing to listen to if (this.subject != null) { - this.engageNonNullSubject(); + this.engageSubject_(); } } /** - * The subject is not null - remove our listener. + * The subject is not null - add our listener. */ - protected abstract void disengageNonNullSubject(); + protected abstract void engageSubject_(); protected void disengageSubject() { // check for nothing to listen to if (this.subject != null) { - this.disengageNonNullSubject(); + this.disengageSubject_(); } } + /** + * The subject is not null - remove our listener. + */ + protected abstract void disengageSubject_(); + protected void engageSubjectHolder() { - this.subjectHolder.addPropertyChangeListener(ValueModel.VALUE, this.subjectChangeListener); + this.subjectHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.subjectChangeListener); // synch our subject *after* we start listening to the subject holder, // since its value might change when a listener is added this.subject = this.subjectHolder.value(); } protected void disengageSubjectHolder() { - this.subjectHolder.removePropertyChangeListener(ValueModel.VALUE, this.subjectChangeListener); + this.subjectHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.subjectChangeListener); // clear out the subject when we are not listening to its holder this.subject = null; } @@ -215,7 +215,7 @@ public abstract class AspectAdapter protected class LocalChangeSupport extends SingleAspectChangeSupport { private static final long serialVersionUID = 1L; - public LocalChangeSupport(AspectAdapter source, Class<? extends ChangeListener> listenerClass, String aspectName) { + public LocalChangeSupport(AspectAdapter<S> source, Class<? extends ChangeListener> listenerClass, String aspectName) { super(source, listenerClass, aspectName); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectPropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectPropertyValueModelAdapter.java new file mode 100644 index 0000000000..2da27fea02 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectPropertyValueModelAdapter.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.model.AbstractModel; +import org.eclipse.jpt.utility.internal.model.ChangeSupport; +import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport; +import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; + +/** + * This abstract class provides the infrastructure needed to wrap + * a value model, "lazily" listen to it, and convert + * its change notifications into property value model change + * notifications. + * + * Subclasses must override: + * - #buildValue() + * to return the current property value, as derived from the + * current model value + * + */ +public abstract class AspectPropertyValueModelAdapter<T> + extends AbstractModel + implements PropertyValueModel<T> +{ + /** + * Cache the current value so we can pass an "old value" when + * we fire a property change event. + * We need this because the value may be calculated and we may + * not able to derive the "old value" from the collection + * change event fired by the collection value model. + */ + protected T value; + + + // ********** constructor/initialization ********** + + protected AspectPropertyValueModelAdapter() { + super(); + // our value is null when we are not listening to the collection holder + this.value = null; + } + + @Override + protected ChangeSupport buildChangeSupport() { + return new SingleAspectChangeSupport(this, PropertyChangeListener.class, VALUE); + } + + + // ********** PropertyValueModel implementation ********** + + /** + * Return the cached value. + */ + public T value() { + return this.value; + } + + + // ********** extend change support ********** + + /** + * Extend to start listening to the wrapped collection if necessary. + */ + @Override + public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { + if (this.hasNoListeners()) { + this.engageModel(); + } + super.addPropertyChangeListener(listener); + } + + /** + * Extend to start listening to the wrapped collection if necessary. + */ + @Override + public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + if (propertyName == VALUE && this.hasNoListeners()) { + this.engageModel(); + } + super.addPropertyChangeListener(propertyName, listener); + } + + /** + * Extend to stop listening to the wrapped collection if necessary. + */ + @Override + public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { + super.removePropertyChangeListener(listener); + if (this.hasNoListeners()) { + this.disengageModel(); + } + } + + /** + * Extend to stop listening to the wrapped collection if necessary. + */ + @Override + public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + super.removePropertyChangeListener(propertyName, listener); + if (propertyName == VALUE && this.hasNoListeners()) { + this.disengageModel(); + } + } + + + // ********** queries ********** + + /** + * Return whether there are any listeners for the aspect. + */ + protected boolean hasListeners() { + return this.hasAnyPropertyChangeListeners(VALUE); + } + + /** + * Return whether there are any listeners for the aspect. + */ + protected boolean hasNoListeners() { + return ! this.hasListeners(); + } + + + // ********** behavior ********** + + /** + * Start listening to the model and build the value. + */ + protected void engageModel() { + this.engageModel_(); + // synch our value *after* we start listening to the collection, + // since the collection's value might change when a listener is added + this.value = this.buildValue(); + } + + /** + * Start listening to the model. + */ + protected abstract void engageModel_(); + + /** + * Build and return the current value, as derived from the + * current state of the wrapped model. + */ + protected abstract T buildValue(); + + /** + * Stop listening to the model and clear the value. + */ + protected void disengageModel() { + this.disengageModel_(); + // clear out our value when we are not listening to the collection + this.value = null; + } + + /** + * Stop listening to the model. + */ + protected abstract void disengageModel_(); + + /** + * The wrapped model changed in some fashion. + * Recalculate the value and notify any listeners. + */ + protected void propertyChanged() { + Object old = this.value; + this.value = this.buildValue(); + this.firePropertyChanged(VALUE, old, this.value); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/BufferedWritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/BufferedWritablePropertyValueModel.java new file mode 100644 index 0000000000..086cd2c154 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/BufferedWritablePropertyValueModel.java @@ -0,0 +1,343 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; + +/** + * A BufferedPropertyValueModel is used to hold a temporary copy of the value + * in another property value model (the "wrapped" value holder). The application + * can modify this temporary copy, ad nauseam; but the temporary copy is only + * passed through to the "wrapped" value holder when the trigger "accepts" the + * buffered value. Alternatively, the application can "reset" the buffered value + * to the original, "wrapped" value. + * + * The trigger is another value model that holds a Boolean and the application + * changes the trigger's value to true on "accept", false on "reset". Typically, + * in a dialog: + * - pressing the OK button will trigger an "accept" and close the dialog + * - pressing the Cancel button will simply close the dialog, + * dropping the "buffered" values into the bit bucket + * - pressing the Apply button will trigger an "accept" and leave the dialog open + * - pressing the Restore button will trigger a "reset" and leave the dialog open + * + * A number of buffered property value models can wrap another set of + * property aspect adapters that adapt the various aspects of a single + * domain model. All the bufferd property value models can be hooked to the + * same trigger, and that trigger is controlled by the application, typically + * via the OK button in a dialog. + * + * @see PropertyAspectAdapter + */ +public class BufferedWritablePropertyValueModel<T> + extends PropertyValueModelWrapper<T> + implements WritablePropertyValueModel<T> +{ + + /** + * We cache the value here until it is accepted and passed + * through to the wrapped value holder. + */ + protected T bufferedValue; + + /** + * This is set to true when we are "accepting" the buffered value + * and passing it through to the wrapped value holder. This allows + * us to ignore the property change event fired by the wrapped + * value holder. + * (We can't stop listening to the wrapped value holder, because + * if we are the only listener that could "deactivate" the wrapped + * value holder.) + */ + protected boolean accepting; + + /** + * This is the trigger that indicates whether the buffered value + * should be accepted or reset. + */ + protected final PropertyValueModel<Boolean> triggerHolder; + + /** This listens to the trigger holder. */ + protected final PropertyChangeListener triggerChangeListener; + + /** + * This flag indicates whether our buffered value has been assigned + * a value and is possibly out of synch with the wrapped value. + */ + protected boolean buffering; + + + // ********** constructors ********** + + /** + * Construct a buffered property value model with the specified wrapped + * property value model and trigger holder. + */ + public BufferedWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder, PropertyValueModel<Boolean> triggerHolder) { + super(valueHolder); + if (triggerHolder == null) { + throw new NullPointerException(); + } + this.triggerHolder = triggerHolder; + this.bufferedValue = null; + this.buffering = false; + this.accepting = false; + this.triggerChangeListener = this.buildTriggerChangeListener(); + } + + + // ********** initialization ********** + + protected PropertyChangeListener buildTriggerChangeListener() { + return new PropertyChangeListener() { + public void propertyChanged(PropertyChangeEvent e) { + BufferedWritablePropertyValueModel.this.triggerChanged(e); + } + @Override + public String toString() { + return "trigger change listener"; + } + }; + } + + + // ********** ValueModel implementation ********** + + /** + * If we are currently "buffering" a value, return that; + * otherwise, return the wrapped value. + */ + public T value() { + return this.buffering ? this.bufferedValue : this.valueHolder.value(); + } + + /** + * Assign the new value to our "buffered" value. + * It will be forwarded to the wrapped value holder + * when the trigger is "accepted". + */ + public void setValue(T value) { + Object old = this.value(); + this.bufferedValue = value; + this.buffering = true; + this.firePropertyChanged(VALUE, old, this.bufferedValue); + } + + + // ********** PropertyValueModelWrapper extensions ********** + + /** + * extend to engage the trigger holder also + */ + @Override + protected void engageValueHolder() { + super.engageValueHolder(); + this.triggerHolder.addPropertyChangeListener(VALUE, this.triggerChangeListener); + } + + /** + * extend to disengage the trigger holder also + */ + @Override + protected void disengageValueHolder() { + this.triggerHolder.removePropertyChangeListener(VALUE, this.triggerChangeListener); + super.disengageValueHolder(); + } + + + // ********** behavior ********** + + /** + * If we do not yet have a "buffered" value, simply propagate the + * change notification with the buffered model as the source. + * If we do have a "buffered" value, do nothing. + */ + @Override + protected void valueChanged(PropertyChangeEvent e) { + if (this.accepting) { + // if we are currently "accepting" the value, ignore change notifications, + // since we caused them and our own listeners are already aware of the change + return; + } + if (this.buffering) { + this.handleChangeConflict(e); + } else { + this.firePropertyChanged(e.cloneWithSource(this)); + } + } + + /** + * By default, if we have a "buffered" value and the "wrapped" value changes, + * we simply ignore the new "wrapped" value and simply overlay it with the + * "buffered" value if it is "accepted". ("Last One In Wins" concurrency model) + * Subclasses can override this method to change that behavior with a + * different concurrency model. For example, you could drop the "buffered" value + * and replace it with the new "wrapped" value, or you could throw an + * exception. + */ + protected void handleChangeConflict(PropertyChangeEvent e) { + // the default is to do nothing + } + + /** + * The trigger changed: + * If it is now true, "accept" the buffered value and forward + * it to the wrapped value holder. + * If it is now false, "reset" the buffered value to its original value. + */ + protected void triggerChanged(PropertyChangeEvent e) { + if ( ! this.buffering) { + // if nothing has been "buffered", we don't need to do anything: + // nothing needs to be passed through; nothing needs to be reset; + return; + } + if (((Boolean) e.newValue()).booleanValue()) { + // set the accepting flag so we ignore any events + // fired by the wrapped value holder + this.accepting = true; + this.valueHolder().setValue(this.bufferedValue); + this.bufferedValue = null; + this.buffering = false; + // clear the flag once the "accept" is complete + this.accepting = false; + } else { + // notify our listeners that our value has been reset + Object old = this.bufferedValue; + this.bufferedValue = null; + this.buffering = false; + this.firePropertyChanged(VALUE, old, this.valueHolder.value()); + } + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.value()); + } + + + // ********** convenience methods ********** + + /** + * Return whether the buffered model is currently "buffering" + * a value. + */ + public boolean isBuffering() { + return this.buffering; + } + + /** + * Our constructor accepts only a WritablePropertyValueModel<T>. + */ + @SuppressWarnings("unchecked") + protected WritablePropertyValueModel<T> valueHolder() { + return (WritablePropertyValueModel<T>) this.valueHolder; + } + + + // ********** inner class ********** + + /** + * Trigger is a special property value model that only maintains its + * value (of true or false) during the change notification caused by + * the #setValue(Object) method. In other words, a Trigger object + * only has a valid value + */ + public static class Trigger extends SimplePropertyValueModel<Boolean> { + + + // ********** constructor ********** + + /** + * Construct a trigger with a null value. + */ + public Trigger() { + super(); + } + + + // ********** ValueModel implementation ********** + + /** + * Extend so that this method can only be invoked during + * change notification triggered by #setValue(Object). + */ + @Override + public Boolean value() { + if (this.value == null) { + throw new IllegalStateException("The method Trigger.value() may only be called during change notification."); + } + return this.value; + } + + /** + * Extend to reset the value to null once all the + * listeners have been notified. + */ + @Override + public void setValue(Boolean value) { + super.setValue(value); + this.value = null; + } + + + // ********** convenience methods ********** + + /** + * Set the trigger's value: + * - true indicates "accept" + * - false indicates "reset" + */ + public void setValue(boolean value) { + this.setValue(Boolean.valueOf(value)); + } + + /** + * Return the trigger's value: + * - true indicates "accept" + * - false indicates "reset" + */ + public boolean booleanValue() { + return this.value().booleanValue(); + } + + /** + * Accept the trigger (i.e. set its value to true). + */ + public void accept() { + this.setValue(true); + } + + /** + * Return whether the trigger has been accepted + * (i.e. its value was changed to true). + */ + public boolean isAccepted() { + return this.booleanValue(); + } + + /** + * Reset the trigger (i.e. set its value to false). + */ + public void reset() { + this.setValue(false); + } + + /** + * Return whether the trigger has been reset + * (i.e. its value was changed to false). + */ + public boolean isReset() { + return ! this.booleanValue(); + } + + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionAspectAdapter.java index b77340b208..5e22ec2598 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionAspectAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionAspectAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,6 +9,8 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; +import java.util.Arrays; +import java.util.Collection; import java.util.Iterator; import org.eclipse.jpt.utility.internal.CollectionTools; @@ -20,6 +22,8 @@ import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; /** * This extension of AspectAdapter provides CollectionChange support. + * This allows us to convert a set of one or more collections into + * a single collection, VALUES. * * The typical subclass will override the following methods: * #iterator_() @@ -36,14 +40,15 @@ import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; * override this method only if returning a zero when the * subject is null is unacceptable */ -public abstract class CollectionAspectAdapter - extends AspectAdapter - implements CollectionValueModel +public abstract class CollectionAspectAdapter<S extends Model, E> + extends AspectAdapter<S> + implements CollectionValueModel<E> { /** - * The name of the subject's collection that we use for the value. + * The name of the subject's collections that we use for the value. */ - protected final String collectionName; + protected final String[] collectionNames; + protected static final String[] EMPTY_COLLECTION_NAMES = new String[0]; /** A listener that listens to the subject's collection aspect. */ protected final CollectionChangeListener collectionChangeListener; @@ -55,30 +60,46 @@ public abstract class CollectionAspectAdapter * Construct a CollectionAspectAdapter for the specified subject * and collection. */ - protected CollectionAspectAdapter(String collectionName, Model subject) { - this(new ReadOnlyPropertyValueModel(subject), collectionName); + protected CollectionAspectAdapter(String collectionName, S subject) { + this(new String[] {collectionName}, subject); } /** - * Construct a CollectionAspectAdapter for an "unchanging" collection in - * the specified subject. This is useful for a collection aspect that does not - * change for a particular subject; but the subject will change, resulting in - * a new collection. + * Construct a CollectionAspectAdapter for the specified subject + * and collections. */ - protected CollectionAspectAdapter(ValueModel subjectHolder) { - this(subjectHolder, null); + protected CollectionAspectAdapter(String[] collectionNames, S subject) { + this(new StaticPropertyValueModel<S>(subject), collectionNames); } /** * Construct a CollectionAspectAdapter for the specified subject holder - * and collection. + * and collections. */ - protected CollectionAspectAdapter(ValueModel subjectHolder, String collectionName) { + protected CollectionAspectAdapter(PropertyValueModel<? extends S> subjectHolder, String... collectionNames) { super(subjectHolder); - this.collectionName = collectionName; + this.collectionNames = collectionNames; this.collectionChangeListener = this.buildCollectionChangeListener(); } + /** + * Construct a CollectionAspectAdapter for the specified subject holder + * and collections. + */ + protected CollectionAspectAdapter(PropertyValueModel<? extends S> subjectHolder, Collection<String> collectionNames) { + this(subjectHolder, collectionNames.toArray(new String[collectionNames.size()])); + } + + /** + * Construct a CollectionAspectAdapter for an "unchanging" collection in + * the specified subject. This is useful for a collection aspect that does not + * change for a particular subject; but the subject will change, resulting in + * a new collection. + */ + protected CollectionAspectAdapter(PropertyValueModel<? extends S> subjectHolder) { + this(subjectHolder, EMPTY_COLLECTION_NAMES); + } + // ********** initialization ********** @@ -102,7 +123,7 @@ public abstract class CollectionAspectAdapter } @Override public String toString() { - return "collection change listener: " + CollectionAspectAdapter.this.collectionName; + return "collection change listener: " + Arrays.asList(CollectionAspectAdapter.this.collectionNames); } }; } @@ -113,8 +134,8 @@ public abstract class CollectionAspectAdapter /** * Return the elements of the subject's collection aspect. */ - public Iterator iterator() { - return (this.subject == null) ? EmptyIterator.instance() : this.iterator_(); + public Iterator<E> iterator() { + return (this.subject == null) ? EmptyIterator.<E>instance() : this.iterator_(); } /** @@ -122,7 +143,7 @@ public abstract class CollectionAspectAdapter * At this point we can be sure that the subject is not null. * @see #iterator() */ - protected Iterator iterator_() { + protected Iterator<E> iterator_() { throw new UnsupportedOperationException(); } @@ -171,22 +192,27 @@ public abstract class CollectionAspectAdapter } @Override - protected void engageNonNullSubject() { - if (this.collectionName != null) { - ((Model) this.subject).addCollectionChangeListener(this.collectionName, this.collectionChangeListener); + protected void engageSubject_() { + for (String collectionName : this.collectionNames) { + ((Model) this.subject).addCollectionChangeListener(collectionName, this.collectionChangeListener); } } @Override - protected void disengageNonNullSubject() { - if (this.collectionName != null) { - ((Model) this.subject).removeCollectionChangeListener(this.collectionName, this.collectionChangeListener); + protected void disengageSubject_() { + for (String collectionName : this.collectionNames) { + ((Model) this.subject).removeCollectionChangeListener(collectionName, this.collectionChangeListener); } } @Override public void toString(StringBuilder sb) { - sb.append(this.collectionName); + for (int i = 0; i < this.collectionNames.length; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(this.collectionNames[i]); + } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionListValueModelAdapter.java index ab1eab80b6..1a1e0ebff6 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionListValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionListValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -11,7 +11,6 @@ package org.eclipse.jpt.utility.internal.model.value; import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import java.util.ListIterator; import org.eclipse.jpt.utility.internal.CollectionTools; @@ -37,12 +36,12 @@ import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; * we do not have any listeners. This should not be too painful since, * most likely, client objects will also be listeners. */ -public class CollectionListValueModelAdapter +public class CollectionListValueModelAdapter<E> extends AbstractModel - implements ListValueModel + implements ListValueModel<E> { /** The wrapped collection value model. */ - protected final CollectionValueModel collectionHolder; + protected final CollectionValueModel<? extends E> collectionHolder; /** A listener that forwards any events fired by the collection holder. */ protected final CollectionChangeListener collectionChangeListener; @@ -52,7 +51,7 @@ public class CollectionListValueModelAdapter * the wrapped collection, but keeps them in order. */ // we declare this an ArrayList so we can use #clone() and #ensureCapacity(int) - protected final ArrayList list; + protected final ArrayList<E> list; // ********** constructors ********** @@ -60,14 +59,14 @@ public class CollectionListValueModelAdapter /** * Wrap the specified CollectionValueModel. */ - public CollectionListValueModelAdapter(CollectionValueModel collectionHolder) { + public CollectionListValueModelAdapter(CollectionValueModel<? extends E> collectionHolder) { super(); if (collectionHolder == null) { throw new NullPointerException(); } this.collectionHolder = collectionHolder; this.collectionChangeListener = this.buildCollectionChangeListener(); - this.list = new ArrayList(); + this.list = new ArrayList<E>(); // postpone building the list and listening to the underlying collection // until we have listeners ourselves... } @@ -108,16 +107,15 @@ public class CollectionListValueModelAdapter // ********** ListValueModel implementation ********** - public Iterator iterator() { + public Iterator<E> iterator() { return this.listIterator(); } - public ListIterator listIterator() { - // try to prevent backdoor modification of the list - return new ReadOnlyListIterator(this.list); + public ListIterator<E> listIterator() { + return new ReadOnlyListIterator<E>(this.list); } - public Object get(int index) { + public E get(int index) { return this.list.get(index); } @@ -212,7 +210,7 @@ public class CollectionListValueModelAdapter // ********** behavior ********** protected void buildList() { - Iterator stream = (Iterator) this.collectionHolder.iterator(); + Iterator<? extends E> stream = this.collectionHolder.iterator(); // if the new collection is empty, do nothing if (stream.hasNext()) { this.list.ensureCapacity(this.collectionHolder.size()); @@ -245,17 +243,22 @@ public class CollectionListValueModelAdapter } protected void itemsAdded(CollectionChangeEvent e) { - this.addItemsToList(this.indexToAddItems(), CollectionTools.list(e.items()), this.list, LIST_VALUES); + this.addItemsToList(this.indexToAddItems(), CollectionTools.list(this.items(e)), this.list, LIST_VALUES); } - protected int indexToAddItems() { - return this.list.size(); - } - + protected int indexToAddItems() { + return this.list.size(); + } + + @SuppressWarnings("unchecked") + protected Iterator<E> items(CollectionChangeEvent e) { + return (Iterator<E>) e.items(); + } + protected void itemsRemoved(CollectionChangeEvent e) { // we have to remove the items individually, // since they are probably not in sequence - for (Iterator stream = e.items(); stream.hasNext(); ) { + for (Iterator<E> stream = this.items(e); stream.hasNext(); ) { this.removeItemFromList(this.lastIdentityIndexOf(stream.next()), this.list, LIST_VALUES); } } @@ -271,7 +274,8 @@ public class CollectionListValueModelAdapter protected void collectionChanged(CollectionChangeEvent e) { // put in empty check so we don't fire events unnecessarily if ( ! this.list.isEmpty()) { - ArrayList removedItems = (ArrayList) this.list.clone(); + @SuppressWarnings("unchecked") + ArrayList<E> removedItems = (ArrayList<E>) this.list.clone(); this.list.clear(); this.fireItemsRemoved(LIST_VALUES, 0, removedItems); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionPropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionPropertyValueModelAdapter.java index a7e34e8d51..b03ebfb4a5 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionPropertyValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionPropertyValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,12 +9,8 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; -import org.eclipse.jpt.utility.internal.model.AbstractModel; -import org.eclipse.jpt.utility.internal.model.ChangeSupport; -import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport; import org.eclipse.jpt.utility.internal.model.event.CollectionChangeEvent; import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; -import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; /** * This abstract class provides the infrastructure needed to wrap @@ -28,28 +24,17 @@ import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; * current collection value * * Subclasses might want to override: - * - #setValue(Object) - * to manipulate the collection in some appropriate fashion * - #itemsAdded(CollectionChangeEvent e) * - #itemsRemoved(CollectionChangeEvent e) + * - #collectionCleared(CollectionChangeEvent e) * - #collectionChanged(CollectionChangeEvent e) * to improve performance (by not recalculating the value, if possible) */ -public abstract class CollectionPropertyValueModelAdapter - extends AbstractModel - implements PropertyValueModel +public abstract class CollectionPropertyValueModelAdapter<T> + extends AspectPropertyValueModelAdapter<T> { - /** - * Cache the current value so we can pass an "old value" when - * we fire a property change event. - * We need this because the value may be calculated and we may - * not able to derive the "old value" from the collection - * change event fired by the collection value model. - */ - protected Object value; - /** The wrapped collection value model. */ - protected final CollectionValueModel collectionHolder; + protected final CollectionValueModel<?> collectionHolder; /** A listener that allows us to synch with changes to the wrapped collection holder. */ protected final CollectionChangeListener collectionChangeListener; @@ -61,19 +46,12 @@ public abstract class CollectionPropertyValueModelAdapter * Construct a property value model with the specified wrapped * collection value model. */ - protected CollectionPropertyValueModelAdapter(CollectionValueModel collectionHolder) { + protected CollectionPropertyValueModelAdapter(CollectionValueModel<?> collectionHolder) { super(); this.collectionHolder = collectionHolder; - // our value is null when we are not listening to the collection holder - this.value = null; this.collectionChangeListener = this.buildCollectionChangeListener(); } - @Override - protected ChangeSupport buildChangeSupport() { - return new SingleAspectChangeSupport(this, PropertyChangeListener.class, VALUE); - } - protected CollectionChangeListener buildCollectionChangeListener() { return new CollectionChangeListener() { public void itemsAdded(CollectionChangeEvent e) { @@ -96,112 +74,22 @@ public abstract class CollectionPropertyValueModelAdapter } - // ********** ValueModel implementation ********** - - /** - * Return the cached value. - */ - public Object value() { - return this.value; - } - - - // ********** PropertyValueModel implementation ********** - - public void setValue(Object value) { - throw new UnsupportedOperationException(); - } - - - // ********** extend change support ********** - - /** - * Extend to start listening to the wrapped collection if necessary. - */ - @Override - public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { - if (this.hasNoListeners()) { - this.engageModel(); - } - super.addPropertyChangeListener(listener); - } - - /** - * Extend to start listening to the wrapped collection if necessary. - */ - @Override - public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { - if (propertyName == VALUE && this.hasNoListeners()) { - this.engageModel(); - } - super.addPropertyChangeListener(propertyName, listener); - } - - /** - * Extend to stop listening to the wrapped collection if necessary. - */ - @Override - public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { - super.removePropertyChangeListener(listener); - if (this.hasNoListeners()) { - this.disengageModel(); - } - } - - /** - * Extend to stop listening to the wrapped collection if necessary. - */ - @Override - public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { - super.removePropertyChangeListener(propertyName, listener); - if (propertyName == VALUE && this.hasNoListeners()) { - this.disengageModel(); - } - } - - - // ********** queries ********** - - /** - * Return whether there are any listeners for the aspect. - */ - protected boolean hasListeners() { - return this.hasAnyPropertyChangeListeners(VALUE); - } - - /** - * Return whether there are any listeners for the aspect. - */ - protected boolean hasNoListeners() { - return ! this.hasListeners(); - } - - // ********** behavior ********** /** * Start listening to the collection holder. */ - protected void engageModel() { + @Override + protected void engageModel_() { this.collectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener); - // synch our value *after* we start listening to the collection, - // since the collection's value might change when a listener is added - this.value = this.buildValue(); } /** - * Build and return the current value, as derived from the - * current state of the wrapped collection. - */ - protected abstract Object buildValue(); - - /** * Stop listening to the collection holder. */ - protected void disengageModel() { + @Override + protected void disengageModel_() { this.collectionHolder.removeCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener); - // clear out our value when we are not listening to the collection - this.value = null; } @Override @@ -248,14 +136,4 @@ public abstract class CollectionPropertyValueModelAdapter this.propertyChanged(); } - /** - * The wrapped collection changed in some fashion. - * Recalculate the value and notify any listeners. - */ - protected void propertyChanged() { - Object old = this.value; - this.value = this.buildValue(); - this.firePropertyChanged(VALUE, old, this.value); - } - } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModel.java index bc17035f97..58c76cc505 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -17,14 +17,14 @@ import org.eclipse.jpt.utility.internal.model.Model; * Interface used to abstract collection accessing and * change notification and make it more pluggable. */ -public interface CollectionValueModel - extends Model//, Iterable<E> +public interface CollectionValueModel<E> + extends Model, Iterable<E> { /** * Return the collection's values. */ - Iterator iterator(); + Iterator<E> iterator(); String VALUES = "values"; /** diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModelWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModelWrapper.java index c1a9b31a92..1ebb7103a6 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModelWrapper.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModelWrapper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,7 +9,6 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; -import java.util.Collection; import java.util.Iterator; import org.eclipse.jpt.utility.internal.model.AbstractModel; @@ -23,13 +22,12 @@ import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; * another collection value model, "lazily" listen to it, and propagate * its change notifications. */ -public abstract class CollectionValueModelWrapper +public abstract class CollectionValueModelWrapper<E> extends AbstractModel - implements CollectionValueModel { /** The wrapped collection value model. */ - protected final CollectionValueModel collectionHolder; + protected final CollectionValueModel<? extends E> collectionHolder; /** A listener that allows us to synch with changes to the wrapped collection holder. */ protected final CollectionChangeListener collectionChangeListener; @@ -41,7 +39,7 @@ public abstract class CollectionValueModelWrapper * Construct a collection value model with the specified wrapped * collection value model. */ - protected CollectionValueModelWrapper(CollectionValueModel collectionHolder) { + protected CollectionValueModelWrapper(CollectionValueModel<? extends E> collectionHolder) { super(); this.collectionHolder = collectionHolder; this.collectionChangeListener = this.buildCollectionChangeListener(); @@ -52,22 +50,22 @@ public abstract class CollectionValueModelWrapper @Override protected ChangeSupport buildChangeSupport() { - return new SingleAspectChangeSupport(this, CollectionChangeListener.class, VALUES); + return new SingleAspectChangeSupport(this, CollectionChangeListener.class, CollectionValueModel.VALUES); } protected CollectionChangeListener buildCollectionChangeListener() { return new CollectionChangeListener() { - public void itemsAdded(CollectionChangeEvent e) { - CollectionValueModelWrapper.this.itemsAdded(e); + public void itemsAdded(CollectionChangeEvent event) { + CollectionValueModelWrapper.this.itemsAdded(event); } - public void itemsRemoved(CollectionChangeEvent e) { - CollectionValueModelWrapper.this.itemsRemoved(e); + public void itemsRemoved(CollectionChangeEvent event) { + CollectionValueModelWrapper.this.itemsRemoved(event); } - public void collectionCleared(CollectionChangeEvent e) { - CollectionValueModelWrapper.this.collectionCleared(e); + public void collectionCleared(CollectionChangeEvent event) { + CollectionValueModelWrapper.this.collectionCleared(event); } - public void collectionChanged(CollectionChangeEvent e) { - CollectionValueModelWrapper.this.collectionChanged(e); + public void collectionChanged(CollectionChangeEvent event) { + CollectionValueModelWrapper.this.collectionChanged(event); } @Override public String toString() { @@ -84,7 +82,7 @@ public abstract class CollectionValueModelWrapper */ @Override public synchronized void addCollectionChangeListener(CollectionChangeListener listener) { - if (this.hasNoCollectionChangeListeners(VALUES)) { + if (this.hasNoCollectionChangeListeners(CollectionValueModel.VALUES)) { this.engageModel(); } super.addCollectionChangeListener(listener); @@ -95,7 +93,7 @@ public abstract class CollectionValueModelWrapper */ @Override public synchronized void addCollectionChangeListener(String collectionName, CollectionChangeListener listener) { - if (collectionName == VALUES && this.hasNoCollectionChangeListeners(VALUES)) { + if (collectionName == CollectionValueModel.VALUES && this.hasNoCollectionChangeListeners(CollectionValueModel.VALUES)) { this.engageModel(); } super.addCollectionChangeListener(collectionName, listener); @@ -107,7 +105,7 @@ public abstract class CollectionValueModelWrapper @Override public synchronized void removeCollectionChangeListener(CollectionChangeListener listener) { super.removeCollectionChangeListener(listener); - if (this.hasNoCollectionChangeListeners(VALUES)) { + if (this.hasNoCollectionChangeListeners(CollectionValueModel.VALUES)) { this.disengageModel(); } } @@ -118,7 +116,7 @@ public abstract class CollectionValueModelWrapper @Override public synchronized void removeCollectionChangeListener(String collectionName, CollectionChangeListener listener) { super.removeCollectionChangeListener(collectionName, listener); - if (collectionName == VALUES && this.hasNoCollectionChangeListeners(VALUES)) { + if (collectionName == CollectionValueModel.VALUES && this.hasNoCollectionChangeListeners(CollectionValueModel.VALUES)) { this.disengageModel(); } } @@ -130,14 +128,20 @@ public abstract class CollectionValueModelWrapper * Start listening to the collection holder. */ protected void engageModel() { - this.collectionHolder.addCollectionChangeListener(VALUES, this.collectionChangeListener); + this.collectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener); } /** * Stop listening to the collection holder. */ protected void disengageModel() { - this.collectionHolder.removeCollectionChangeListener(VALUES, this.collectionChangeListener); + this.collectionHolder.removeCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener); + } + + // minimize suppressed warnings + @SuppressWarnings("unchecked") + protected Iterator<E> items(CollectionChangeEvent event) { + return (Iterator<E>) event.items(); } @Override @@ -152,24 +156,24 @@ public abstract class CollectionValueModelWrapper * Items were added to the wrapped collection holder; * propagate the change notification appropriately. */ - protected abstract void itemsAdded(CollectionChangeEvent e); + protected abstract void itemsAdded(CollectionChangeEvent event); /** * Items were removed from the wrapped collection holder; * propagate the change notification appropriately. */ - protected abstract void itemsRemoved(CollectionChangeEvent e); + protected abstract void itemsRemoved(CollectionChangeEvent event); /** * The wrapped collection holder was cleared; * propagate the change notification appropriately. */ - protected abstract void collectionCleared(CollectionChangeEvent e); + protected abstract void collectionCleared(CollectionChangeEvent event); /** * The value of the wrapped collection holder has changed; * propagate the change notification appropriately. */ - protected abstract void collectionChanged(CollectionChangeEvent e); + protected abstract void collectionChanged(CollectionChangeEvent event); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeCollectionValueModel.java index 2fd599019e..29a0f0feff 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeCollectionValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeCollectionValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -35,28 +35,29 @@ import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; * - components - the component collection value models that are combined * by this composite collection value model */ -public class CompositeCollectionValueModel - extends CollectionValueModelWrapper +public class CompositeCollectionValueModel<T, E> + extends CollectionValueModelWrapper<T> + implements CollectionValueModel<E> { /** * This is the (optional) user-supplied object that transforms * the items in the wrapped collection to collection value models. */ - private final Transformer transformer; + private final Transformer<T, CollectionValueModel<E>> transformer; /** * Cache of the component collection value models that * were generated by the transformer; keyed by the item * in the wrapped collection that was passed to the transformer. */ - private final IdentityHashMap components; + private final IdentityHashMap<T, CollectionValueModel<E>> components; /** * Cache of the collections corresponding to the component * collection value models above; keyed by the component * collection value models. */ - private final IdentityHashMap collections; + private final IdentityHashMap<CollectionValueModel<E>, ArrayList<E>> collections; /** Listener that listens to all the component collection value models. */ private final CollectionChangeListener componentListener; @@ -73,19 +74,19 @@ public class CompositeCollectionValueModel * <code>transform(Object)</code> method instead of building a * <code>Transformer</code>. */ - public CompositeCollectionValueModel(CollectionValueModel collectionHolder) { - this(collectionHolder, Transformer.Disabled.instance()); + public CompositeCollectionValueModel(CollectionValueModel<? extends T> collectionHolder) { + this(collectionHolder, Transformer.Disabled.<T, CollectionValueModel<E>>instance()); } /** * Construct a collection value model with the specified wrapped * collection value model and transformer. */ - public CompositeCollectionValueModel(CollectionValueModel collectionHolder, Transformer transformer) { + public CompositeCollectionValueModel(CollectionValueModel<? extends T> collectionHolder, Transformer<T, CollectionValueModel<E>> transformer) { super(collectionHolder); this.transformer = transformer; - this.components = new IdentityHashMap(); - this.collections = new IdentityHashMap(); + this.components = new IdentityHashMap<T, CollectionValueModel<E>>(); + this.collections = new IdentityHashMap<CollectionValueModel<E>, ArrayList<E>>(); this.componentListener = this.buildComponentListener(); this.size = 0; } @@ -96,16 +97,16 @@ public class CompositeCollectionValueModel * <code>transform(Object)</code> method instead of building a * <code>Transformer</code>. */ - public CompositeCollectionValueModel(ListValueModel listHolder) { - this(new ListCollectionValueModelAdapter(listHolder)); + public CompositeCollectionValueModel(ListValueModel<? extends T> listHolder) { + this(new ListCollectionValueModelAdapter<T>(listHolder)); } /** * Construct a collection value model with the specified wrapped * list value model and transformer. */ - public CompositeCollectionValueModel(ListValueModel listHolder, Transformer transformer) { - this(new ListCollectionValueModelAdapter(listHolder), transformer); + public CompositeCollectionValueModel(ListValueModel<? extends T> listHolder, Transformer<T, CollectionValueModel<E>> transformer) { + this(new ListCollectionValueModelAdapter<T>(listHolder), transformer); } @@ -135,14 +136,15 @@ public class CompositeCollectionValueModel // ********** CollectionValueModel implementation ********** - public Iterator iterator() { - return new CompositeIterator(this.buildCollectionsIterators()); + public Iterator<E> iterator() { + return new CompositeIterator<E>(this.buildCollectionsIterators()); } - protected Iterator buildCollectionsIterators() { - return new TransformationIterator(this.collections.values().iterator()) { - protected Object transform(Object next) { - return ((ArrayList) next).iterator(); + protected Iterator<Iterator<E>> buildCollectionsIterators() { + return new TransformationIterator<ArrayList<E>, Iterator<E>>(this.collections.values().iterator()) { + @Override + protected Iterator<E> transform(ArrayList<E> next) { + return next.iterator(); } }; } @@ -162,15 +164,15 @@ public class CompositeCollectionValueModel // the following will trigger the firing of a number of unnecessary events // (since we don't have any listeners yet), // but it reduces the amount of duplicate code - this.addComponentSources((Iterator) this.collectionHolder.iterator()); + this.addComponentSources(this.collectionHolder.iterator()); } @Override protected void disengageModel() { super.disengageModel(); // stop listening to the components... - for (Iterator stream = this.components.values().iterator(); stream.hasNext(); ) { - ((CollectionValueModel) stream.next()).removeCollectionChangeListener(CollectionValueModel.VALUES, this.componentListener); + for (CollectionValueModel<E> cvm : this.components.values()) { + cvm.removeCollectionChangeListener(CollectionValueModel.VALUES, this.componentListener); } // ...and clear the cache this.components.clear(); @@ -184,14 +186,14 @@ public class CompositeCollectionValueModel */ @Override protected void itemsAdded(CollectionChangeEvent e) { - this.addComponentSources(e.items()); + this.addComponentSources(this.items(e)); } /** * Transform the specified sources to collection value models * and add their items to our cache. */ - protected void addComponentSources(Iterator sources) { + protected void addComponentSources(Iterator<? extends T> sources) { while (sources.hasNext()) { this.addComponentSource(sources.next()); } @@ -201,13 +203,13 @@ public class CompositeCollectionValueModel * Transform the specified source to a collection value model * and add its items to our cache. */ - protected void addComponentSource(Object source) { - CollectionValueModel component = this.transform(source); + protected void addComponentSource(T source) { + CollectionValueModel<E> component = this.transform(source); if (this.components.put(source, component) != null) { throw new IllegalStateException("duplicate component: " + source); } component.addCollectionChangeListener(CollectionValueModel.VALUES, this.componentListener); - ArrayList componentCollection = new ArrayList(component.size()); + ArrayList<E> componentCollection = new ArrayList<E>(component.size()); if (this.collections.put(component, componentCollection) != null) { throw new IllegalStateException("duplicate collection: " + source); } @@ -220,14 +222,14 @@ public class CompositeCollectionValueModel */ @Override protected void itemsRemoved(CollectionChangeEvent e) { - this.removeComponentSources(e.items()); + this.removeComponentSources(this.items(e)); } /** * Remove the items corresponding to the specified sources * from our cache. */ - protected void removeComponentSources(Iterator sources) { + protected void removeComponentSources(Iterator<T> sources) { while (sources.hasNext()) { this.removeComponentSource(sources.next()); } @@ -237,13 +239,13 @@ public class CompositeCollectionValueModel * Remove the items corresponding to the specified source * from our cache. */ - protected void removeComponentSource(Object source) { - CollectionValueModel component = (CollectionValueModel) this.components.remove(source); + protected void removeComponentSource(T source) { + CollectionValueModel<E> component = this.components.remove(source); if (component == null) { throw new IllegalStateException("missing component: " + source); } component.removeCollectionChangeListener(CollectionValueModel.VALUES, this.componentListener); - ArrayList componentCollection = (ArrayList) this.collections.remove(component); + ArrayList<E> componentCollection = this.collections.remove(component); if (componentCollection == null) { throw new IllegalStateException("missing collection: " + source); } @@ -257,7 +259,7 @@ public class CompositeCollectionValueModel @Override protected void collectionCleared(CollectionChangeEvent e) { // copy the keys so we don't eat our own tail - this.removeComponentSources(new ArrayList(this.components.keySet()).iterator()); + this.removeComponentSources(new ArrayList<T>(this.components.keySet()).iterator()); } /** @@ -267,8 +269,8 @@ public class CompositeCollectionValueModel @Override protected void collectionChanged(CollectionChangeEvent e) { // copy the keys so we don't eat our own tail - this.removeComponentSources(new ArrayList(this.components.keySet()).iterator()); - this.addComponentSources((Iterator) this.collectionHolder.iterator()); + this.removeComponentSources(new ArrayList<T>(this.components.keySet()).iterator()); + this.addComponentSources(this.collectionHolder.iterator()); } @@ -279,8 +281,8 @@ public class CompositeCollectionValueModel * Cast to ArrayList so we can use ArrayList-specific methods * (e.g. #clone() and #ensureCapacity()). */ - protected ArrayList getComponentCollection(CollectionValueModel collectionValueModel) { - return (ArrayList) this.collections.get(collectionValueModel); + protected ArrayList<E> componentCollection(CollectionValueModel<E> collectionValueModel) { + return this.collections.get(collectionValueModel); } @@ -292,8 +294,8 @@ public class CompositeCollectionValueModel * This method can be overridden by a subclass as an * alternative to building a <code>Transformer</code>. */ - protected CollectionValueModel transform(Object value) { - return (CollectionValueModel) this.transformer.transform(value); + protected CollectionValueModel<E> transform(T value) { + return this.transformer.transform(value); } /** @@ -301,27 +303,27 @@ public class CompositeCollectionValueModel * synchronize our caches. */ protected void componentItemsAdded(CollectionChangeEvent e) { - this.addComponentItems(e.items(), e.itemsSize(), (CollectionValueModel) e.getSource()); + this.addComponentItems(this.componentItems(e), e.itemsSize(), this.componentCVM(e)); } /** * Update our cache. */ - protected void addComponentItems(Iterator items, int itemsSize, CollectionValueModel cvm) { - this.addComponentItems(items, itemsSize, this.getComponentCollection(cvm)); + protected void addComponentItems(Iterator<E> items, int itemsSize, CollectionValueModel<E> cvm) { + this.addComponentItems(items, itemsSize, this.componentCollection(cvm)); } /** * Update our cache. */ - protected void addComponentItems(CollectionValueModel itemsHolder, ArrayList componentCollection) { - this.addComponentItems((Iterator) itemsHolder.iterator(), itemsHolder.size(), componentCollection); + protected void addComponentItems(CollectionValueModel<E> itemsHolder, ArrayList<E> componentCollection) { + this.addComponentItems(itemsHolder.iterator(), itemsHolder.size(), componentCollection); } /** * Update our size and collection cache. */ - protected void addComponentItems(Iterator items, int itemsSize, ArrayList componentCollection) { + protected void addComponentItems(Iterator<E> items, int itemsSize, ArrayList<E> componentCollection) { this.size += itemsSize; componentCollection.ensureCapacity(componentCollection.size() + itemsSize); this.addItemsToCollection(items, componentCollection, CollectionValueModel.VALUES); @@ -332,28 +334,29 @@ public class CompositeCollectionValueModel * synchronize our caches. */ protected void componentItemsRemoved(CollectionChangeEvent e) { - this.removeComponentItems(e.items(), e.itemsSize(), (CollectionValueModel) e.getSource()); + this.removeComponentItems(this.componentItems(e), e.itemsSize(), this.componentCVM(e)); } /** * Update our size and collection cache. */ - protected void removeComponentItems(Iterator items, int itemsSize, CollectionValueModel cvm) { - this.removeComponentItems(items, itemsSize, this.getComponentCollection(cvm)); + protected void removeComponentItems(Iterator<E> items, int itemsSize, CollectionValueModel<E> cvm) { + this.removeComponentItems(items, itemsSize, this.componentCollection(cvm)); } /** * Update our size and collection cache. */ - protected void clearComponentItems(ArrayList items) { + protected void clearComponentItems(ArrayList<E> items) { // clone the collection so we don't eat our own tail - this.removeComponentItems(((ArrayList) items.clone()).iterator(), items.size(), items); + @SuppressWarnings("unchecked") ArrayList<E> clone = (ArrayList<E>) items.clone(); + this.removeComponentItems(clone.iterator(), items.size(), items); } /** * Update our size and collection cache. */ - protected void removeComponentItems(Iterator items, int itemsSize, ArrayList componentCollection) { + protected void removeComponentItems(Iterator<E> items, int itemsSize, ArrayList<E> componentCollection) { this.size -= itemsSize; this.removeItemsFromCollection(items, componentCollection, CollectionValueModel.VALUES); } @@ -364,8 +367,7 @@ public class CompositeCollectionValueModel * collection. */ protected void componentCollectionCleared(CollectionChangeEvent e) { - CollectionValueModel component = (CollectionValueModel) e.getSource(); - ArrayList items = this.getComponentCollection(component); + ArrayList<E> items = this.componentCollection(this.componentCVM(e)); this.clearComponentItems(items); } @@ -375,10 +377,22 @@ public class CompositeCollectionValueModel * collection and then rebuilding it. */ protected void componentCollectionChanged(CollectionChangeEvent e) { - CollectionValueModel component = (CollectionValueModel) e.getSource(); - ArrayList items = this.getComponentCollection(component); + CollectionValueModel<E> componentCVM = this.componentCVM(e); + ArrayList<E> items = this.componentCollection(componentCVM); this.clearComponentItems(items); - this.addComponentItems(component, items); + this.addComponentItems(componentCVM, items); + } + + // minimize suppressed warnings + @SuppressWarnings("unchecked") + protected Iterator<E> componentItems(CollectionChangeEvent e) { + return (Iterator<E>) e.items(); + } + + // minimize suppressed warnings + @SuppressWarnings("unchecked") + protected CollectionValueModel<E> componentCVM(CollectionChangeEvent e) { + return (CollectionValueModel<E>) e.getSource(); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ExtendedListValueModelWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ExtendedListValueModelWrapper.java index da5a33401f..1d69c3e39c 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ExtendedListValueModelWrapper.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ExtendedListValueModelWrapper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -16,7 +16,7 @@ import java.util.List; import java.util.ListIterator; import org.eclipse.jpt.utility.internal.CollectionTools; -import org.eclipse.jpt.utility.internal.iterators.CompositeListIterator; +import org.eclipse.jpt.utility.internal.iterators.ReadOnlyCompositeListIterator; import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator; import org.eclipse.jpt.utility.internal.model.event.ListChangeEvent; @@ -27,14 +27,15 @@ import org.eclipse.jpt.utility.internal.model.event.ListChangeEvent; * NB: Be careful using or wrapping this list value model, since the * "extended" items may be unexpected by the client code or wrapper. */ -public class ExtendedListValueModelWrapper - extends ListValueModelWrapper +public class ExtendedListValueModelWrapper<E> + extends ListValueModelWrapper<E> + implements ListValueModel<E> { /** the items "prepended" to the wrapped list */ - protected List prefix; + protected List<E> prefix; /** the items "appended" to the wrapped list */ - protected List suffix; + protected List<E> suffix; // ********** lots o' constructors ********** @@ -42,16 +43,16 @@ public class ExtendedListValueModelWrapper /** * Extend the specified list with a prefix and suffix. */ - public ExtendedListValueModelWrapper(List prefix, ListValueModel listHolder, List suffix) { + public ExtendedListValueModelWrapper(List<? extends E> prefix, ListValueModel<? extends E> listHolder, List<? extends E> suffix) { super(listHolder); - this.prefix = new ArrayList(prefix); - this.suffix = new ArrayList(suffix); + this.prefix = new ArrayList<E>(prefix); + this.suffix = new ArrayList<E>(suffix); } /** * Extend the specified list with a prefix and suffix. */ - public ExtendedListValueModelWrapper(Object prefix, ListValueModel listHolder, Object suffix) { + public ExtendedListValueModelWrapper(E prefix, ListValueModel<? extends E> listHolder, E suffix) { super(listHolder); this.prefix = Collections.singletonList(prefix); this.suffix = Collections.singletonList(suffix); @@ -60,68 +61,69 @@ public class ExtendedListValueModelWrapper /** * Extend the specified list with a prefix. */ - public ExtendedListValueModelWrapper(List prefix, ListValueModel listHolder) { + public ExtendedListValueModelWrapper(List<? extends E> prefix, ListValueModel<? extends E> listHolder) { super(listHolder); - this.prefix = new ArrayList(prefix); - this.suffix = Collections.EMPTY_LIST; + this.prefix = new ArrayList<E>(prefix); + this.suffix = Collections.emptyList(); } /** * Extend the specified list with a prefix. */ - public ExtendedListValueModelWrapper(Object prefix, ListValueModel listHolder) { + public ExtendedListValueModelWrapper(E prefix, ListValueModel<? extends E> listHolder) { super(listHolder); this.prefix = Collections.singletonList(prefix); - this.suffix = Collections.EMPTY_LIST; + this.suffix = Collections.emptyList(); } /** * Extend the specified list with a suffix. */ - public ExtendedListValueModelWrapper(ListValueModel listHolder, List suffix) { + public ExtendedListValueModelWrapper(ListValueModel<? extends E> listHolder, List<? extends E> suffix) { super(listHolder); - this.prefix = Collections.EMPTY_LIST; - this.suffix = new ArrayList(suffix); + this.prefix = Collections.emptyList(); + this.suffix = new ArrayList<E>(suffix); } /** * Extend the specified list with a suffix. */ - public ExtendedListValueModelWrapper(ListValueModel listHolder, Object suffix) { + public ExtendedListValueModelWrapper(ListValueModel<? extends E> listHolder, E suffix) { super(listHolder); - this.prefix = Collections.EMPTY_LIST; + this.prefix = Collections.emptyList(); this.suffix = Collections.singletonList(suffix); } /** * Extend the specified list with a prefix containing a single null item. */ - public ExtendedListValueModelWrapper(ListValueModel listHolder) { + public ExtendedListValueModelWrapper(ListValueModel<? extends E> listHolder) { super(listHolder); this.prefix = Collections.singletonList(null); - this.suffix = Collections.EMPTY_LIST; + this.suffix = Collections.emptyList(); } // ********** ListValueModel implementation ********** - public Iterator iterator() { + public Iterator<E> iterator() { return this.listIterator(); } - public ListIterator listIterator() { - // try to prevent backdoor modification of the lists - return new ReadOnlyListIterator( - new CompositeListIterator( - this.prefix.listIterator(), - this.listHolder.listIterator(), - this.suffix.listIterator() - ) + public ListIterator<E> listIterator() { + return new ReadOnlyListIterator<E>(this.listIterator_()); + } + + @SuppressWarnings("unchecked") + protected ListIterator<E> listIterator_() { + return new ReadOnlyCompositeListIterator<E>( + this.prefix.listIterator(), + this.listHolder.listIterator(), + this.suffix.listIterator() ); } - @Override - public Object get(int index) { + public E get(int index) { int prefixSize = this.prefix.size(); if (index < prefixSize) { return this.prefix.get(index); @@ -132,14 +134,12 @@ public class ExtendedListValueModelWrapper } } - @Override public int size() { return this.prefix.size() + this.listHolder.size() + this.suffix.size(); } - @Override public Object[] toArray() { - ArrayList list = new ArrayList(this.size()); + ArrayList<E> list = new ArrayList<E>(this.size()); list.addAll(this.prefix); CollectionTools.addAll(list, this.listHolder.iterator()); list.addAll(this.suffix); @@ -191,12 +191,12 @@ public class ExtendedListValueModelWrapper // ********** miscellaneous ********** - public void setPrefix(List prefix) { + public void setPrefix(List<E> prefix) { this.prefix = prefix; this.fireListChanged(LIST_VALUES); } - public void setSuffix(List suffix) { + public void setSuffix(List<E> suffix) { this.suffix = suffix; this.fireListChanged(LIST_VALUES); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringCollectionValueModel.java index fadfcaf6ae..e645484d6f 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringCollectionValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringCollectionValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -40,14 +40,15 @@ import org.eclipse.jpt.utility.internal.model.event.CollectionChangeEvent; * changes. The event will cause this wrapper to re-filter the changed * item and add or remove it from the "filtered" collection as appropriate. */ -public class FilteringCollectionValueModel - extends CollectionValueModelWrapper +public class FilteringCollectionValueModel<E> + extends CollectionValueModelWrapper<E> + implements CollectionValueModel<E> { /** This filters the items in the nested collection. */ - private Filter filter; + private Filter<E> filter; /** Cache the items that were accepted by the filter */ - private final Collection filteredItems; + private final Collection<E> filteredItems; // ********** constructors ********** @@ -56,41 +57,41 @@ public class FilteringCollectionValueModel * Construct a collection value model with the specified wrapped * collection value model and a filter that simply accepts every object. */ - public FilteringCollectionValueModel(CollectionValueModel collectionHolder) { - this(collectionHolder, Filter.Null.instance()); + public FilteringCollectionValueModel(CollectionValueModel<? extends E> collectionHolder) { + this(collectionHolder, Filter.Null.<E>instance()); } /** * Construct a collection value model with the specified wrapped * collection value model and filter. */ - public FilteringCollectionValueModel(CollectionValueModel collectionHolder, Filter filter) { + public FilteringCollectionValueModel(CollectionValueModel<? extends E> collectionHolder, Filter<E> filter) { super(collectionHolder); this.filter = filter; - this.filteredItems = new ArrayList(); + this.filteredItems = new ArrayList<E>(); } /** * Construct a collection value model with the specified wrapped * list value model and a filter that simply accepts every object. */ - public FilteringCollectionValueModel(ListValueModel listHolder) { - this(new ListCollectionValueModelAdapter(listHolder)); + public FilteringCollectionValueModel(ListValueModel<E> listHolder) { + this(new ListCollectionValueModelAdapter<E>(listHolder)); } /** * Construct a collection value model with the specified wrapped * list value model and filter. */ - public FilteringCollectionValueModel(ListValueModel listHolder, Filter filter) { - this(new ListCollectionValueModelAdapter(listHolder), filter); + public FilteringCollectionValueModel(ListValueModel<E> listHolder, Filter<E> filter) { + this(new ListCollectionValueModelAdapter<E>(listHolder), filter); } // ********** CollectionValueModel implementation ********** - public Iterator iterator() { - return new ReadOnlyIterator(this.filteredItems); + public Iterator<E> iterator() { + return new ReadOnlyIterator<E>(this.filteredItems); } public int size() { @@ -118,7 +119,7 @@ public class FilteringCollectionValueModel @Override protected void itemsAdded(CollectionChangeEvent e) { // filter the values before propagating the change event - this.addItemsToCollection(this.filter(e.items()), this.filteredItems, VALUES); + this.addItemsToCollection(this.filter(this.items(e)), this.filteredItems, VALUES); } @Override @@ -145,7 +146,7 @@ public class FilteringCollectionValueModel /** * Change the filter and rebuild the collection. */ - public void setFilter(Filter filter) { + public void setFilter(Filter<E> filter) { this.filter = filter; this.rebuildFilteredItems(); } @@ -153,8 +154,8 @@ public class FilteringCollectionValueModel /** * Return an iterator that filters the specified iterator. */ - protected Iterator filter(Iterator items) { - return new FilteringIterator(items, this.filter); + protected Iterator<E> filter(Iterator<? extends E> items) { + return new FilteringIterator<E, E>(items, this.filter); } /** diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringPropertyValueModel.java index 2d5e192bd9..6ac16b63e7 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringPropertyValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringPropertyValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,34 +9,30 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; -import org.eclipse.jpt.utility.internal.BidiFilter; +import org.eclipse.jpt.utility.internal.Filter; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; /** * A <code>FilteringPropertyValueModel</code> wraps another - * <code>PropertyValueModel</code> and uses a <code>BidiFilter</code> + * <code>PropertyValueModel</code> and uses a <code>Filter</code> * to determine when the wrapped value is to be returned by calls - * to <code>value()</code> and modified by calls to - * <code>setValue(Object)</code> + * to <code>value()</code>. * <p> - * As an alternative to building a <code>BidiFilter</code>, a subclass + * As an alternative to building a <code>Filter</code>, a subclass * of <code>FilteringPropertyValueModel</code> can override the - * <code>accept(Object)</code> and <code>reverseAccept(Object)</code> - * methods. + * <code>accept(Object)</code> method. * <p> * One, possibly undesirable, side-effect of using this value model is that * it must return *something* as the value. The default behavior is * to return <code>null</code> whenever the wrapped value is not "accepted", * which can be configured and/or overridden. - * <p> - * Likewise, if an incoming value is not "reverseAccepted", *nothing* will passed - * through to the wrapped value holder, not even <code>null</code>. */ -public class FilteringPropertyValueModel - extends PropertyValueModelWrapper +public class FilteringPropertyValueModel<T> + extends PropertyValueModelWrapper<T> + implements PropertyValueModel<T> { - private final BidiFilter filter; - private final Object defaultValue; + protected final Filter<T> filter; + protected final T defaultValue; // ********** constructors ********** @@ -45,25 +41,25 @@ public class FilteringPropertyValueModel * Construct a property value model with the specified nested * property value model and a disabled filter. * Use this constructor if you want to override the - * <code>accept(Object)</code> and <code>reverseAccept(Object)</code> - * methods instead of building a <code>BidiFilter</code>. + * <code>accept(Object)</code> + * method instead of building a <code>Filter</code>. * The default value will be <code>null</code>. */ - public FilteringPropertyValueModel(PropertyValueModel valueHolder) { - this(valueHolder, BidiFilter.Disabled.instance(), null); + public FilteringPropertyValueModel(PropertyValueModel<? extends T> valueHolder) { + this(valueHolder, Filter.Disabled.<T>instance(), null); } /** * Construct a property value model with the specified nested * property value model, specified default value, and a disabled filter. * Use this constructor if you want to override the - * <code>accept(Object)</code> and <code>reverseAccept(Object)</code> - * methods instead of building a <code>BidiFilter</code> + * <code>accept(Object)</code> + * method instead of building a <code>Filter</code> * <em>and</em> you need to specify * a default value other than <code>null</code>. */ - public FilteringPropertyValueModel(PropertyValueModel valueHolder, Object defaultValue) { - this(valueHolder, BidiFilter.Disabled.instance(), defaultValue); + public FilteringPropertyValueModel(PropertyValueModel<? extends T> valueHolder, T defaultValue) { + this(valueHolder, Filter.Disabled.<T>instance(), defaultValue); } /** @@ -71,7 +67,7 @@ public class FilteringPropertyValueModel * property value model and filter. * The default value will be <code>null</code>. */ - public FilteringPropertyValueModel(PropertyValueModel valueHolder, BidiFilter filter) { + public FilteringPropertyValueModel(PropertyValueModel<? extends T> valueHolder, Filter<T> filter) { this(valueHolder, filter, null); } @@ -79,26 +75,17 @@ public class FilteringPropertyValueModel * Construct an property value model with the specified nested * property value model, filter, and default value. */ - public FilteringPropertyValueModel(PropertyValueModel valueHolder, BidiFilter filter, Object defaultValue) { + public FilteringPropertyValueModel(PropertyValueModel<? extends T> valueHolder, Filter<T> filter, T defaultValue) { super(valueHolder); this.filter = filter; this.defaultValue = defaultValue; } - // ********** ValueModel implementation ********** - - public Object value() { - return this.filterValue(this.valueHolder.value()); - } - - // ********** PropertyValueModel implementation ********** - public void setValue(Object value) { - if (this.reverseAccept(value)) { - this.valueHolder.setValue(value); - } + public T value() { + return this.filterValue(this.valueHolder.value()); } @@ -107,8 +94,10 @@ public class FilteringPropertyValueModel @Override protected void valueChanged(PropertyChangeEvent e) { // filter the values before propagating the change event - Object oldValue = this.filterValue(e.oldValue()); - Object newValue = this.filterValue(e.newValue()); + @SuppressWarnings("unchecked") + Object oldValue = this.filterValue((T) e.oldValue()); + @SuppressWarnings("unchecked") + Object newValue = this.filterValue((T) e.newValue()); this.firePropertyChanged(VALUE, oldValue, newValue); } @@ -119,7 +108,7 @@ public class FilteringPropertyValueModel * If the specified value is "accepted" simply return it, * otherwise return the default value. */ - protected Object filterValue(Object value) { + protected T filterValue(T value) { return this.accept(value) ? value : this.defaultValue(); } @@ -130,31 +119,18 @@ public class FilteringPropertyValueModel * from the nested property value model * <p> * This method can be overridden by a subclass as an - * alternative to building a <code>BidiFilter</code>. + * alternative to building a <code>Filter</code>. */ - protected boolean accept(Object value) { + protected boolean accept(T value) { return this.filter.accept(value); } /** - * Return whether the <code>FilteringPropertyValueModel</code> - * should pass through the specified value to the nested - * property value model in a call to the - * <code>setValue(Object)</code> method - * <p> - * This method can be overridden by a subclass as an - * alternative to building a <code>BidiFilter</code>. - */ - protected boolean reverseAccept(Object value) { - return this.filter.reverseAccept(value); - } - - /** * Return the object that should be returned if * the nested value was rejected by the filter. * The default is <code>null</code>. */ - protected Object defaultValue() { + protected T defaultValue() { return this.defaultValue; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringWritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringWritablePropertyValueModel.java new file mode 100644 index 0000000000..96ca481ba2 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringWritablePropertyValueModel.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.BidiFilter; + +/** + * A <code>FilteringWritablePropertyValueModel</code> wraps another + * <code>WritabelPropertyValueModel</code> and uses a <code>BidiFilter</code> + * to determine when the wrapped value is to be returned by calls + * to <code>value()</code> and modified by calls to + * <code>setValue(Object)</code>. + * <p> + * As an alternative to building a <code>BidiFilter</code>, a subclass + * of <code>FilteringWritablePropertyValueModel</code> can override the + * <code>accept(Object)</code> and <code>reverseAccept(Object)</code> + * methods. + * <p> + * One, possibly undesirable, side-effect of using this value model is that + * it must return *something* as the value. The default behavior is + * to return <code>null</code> whenever the wrapped value is not "accepted", + * which can be configured and/or overridden. + * <p> + * Similarly, if an incoming value is not "reverseAccepted", *nothing* will passed + * through to the wrapped value holder, not even <code>null</code>. + */ +public class FilteringWritablePropertyValueModel<T> + extends FilteringPropertyValueModel<T> + implements WritablePropertyValueModel<T> +{ + + + // ********** constructors ********** + + /** + * Construct a property value model with the specified nested + * property value model and a disabled filter. + * Use this constructor if you want to override the + * <code>accept(Object)</code> and <code>reverseAccept(Object)</code> + * methods instead of building a <code>BidiFilter</code>. + * The default value will be <code>null</code>. + */ + public FilteringWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder) { + this(valueHolder, BidiFilter.Disabled.<T>instance(), null); + } + + /** + * Construct a property value model with the specified nested + * property value model, specified default value, and a disabled filter. + * Use this constructor if you want to override the + * <code>accept(Object)</code> and <code>reverseAccept(Object)</code> + * methods instead of building a <code>BidiFilter</code> + * <em>and</em> you need to specify + * a default value other than <code>null</code>. + */ + public FilteringWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder, T defaultValue) { + this(valueHolder, BidiFilter.Disabled.<T>instance(), defaultValue); + } + + /** + * Construct an property value model with the specified nested + * property value model and filter. + * The default value will be <code>null</code>. + */ + public FilteringWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder, BidiFilter<T> filter) { + this(valueHolder, filter, null); + } + + /** + * Construct an property value model with the specified nested + * property value model, filter, and default value. + */ + public FilteringWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder, BidiFilter<T> filter, T defaultValue) { + super(valueHolder, filter, defaultValue); + } + + + // ********** WritablePropertyValueModel implementation ********** + + public void setValue(T value) { + if (this.reverseAccept(value)) { + this.valueHolder().setValue(value); + } + } + + + // ********** queries ********** + + /** + * Return whether the <code>FilteringWritablePropertyValueModel</code> + * should pass through the specified value to the nested + * writable property value model in a call to the + * <code>setValue(Object)</code> method + * <p> + * This method can be overridden by a subclass as an + * alternative to building a <code>BidiFilter</code>. + */ + protected boolean reverseAccept(T value) { + return this.filter().reverseAccept(value); + } + + /** + * Our constructors accept only a WritablePropertyValueModel<T>. + */ + @SuppressWarnings("unchecked") + protected WritablePropertyValueModel<T> valueHolder() { + return (WritablePropertyValueModel<T>) this.valueHolder; + } + + /** + * Our constructors accept only a bidirectional filter. + */ + protected BidiFilter<T> filter() { + return (BidiFilter<T>) this.filter; + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemAspectListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemAspectListValueModelAdapter.java index 3cc7ba5768..2460a1d814 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemAspectListValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemAspectListValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -17,6 +17,7 @@ import java.util.Iterator; import java.util.ListIterator; import org.eclipse.jpt.utility.internal.Counter; +import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator; import org.eclipse.jpt.utility.internal.model.Model; import org.eclipse.jpt.utility.internal.model.event.ListChangeEvent; @@ -32,22 +33,23 @@ import org.eclipse.jpt.utility.internal.model.event.ListChangeEvent; * * Subclasses need to override two methods: * - * listenToItem(Model) + * #listenToItem(Model) * begin listening to the appropriate aspect of the specified item and call * #itemAspectChanged(Object) whenever the aspect changes * - * stopListeningToItem(Model) + * #stopListeningToItem(Model) * stop listening to the appropriate aspect of the specified item */ -public abstract class ItemAspectListValueModelAdapter - extends ListValueModelWrapper +public abstract class ItemAspectListValueModelAdapter<E> + extends ListValueModelWrapper<E> + implements ListValueModel<E> { /** * Maintain a counter for each of the items in the * wrapped list holder we are listening to. */ - protected final IdentityHashMap counters; + protected final IdentityHashMap<E, Counter> counters; // ********** constructors ********** @@ -55,36 +57,37 @@ public abstract class ItemAspectListValueModelAdapter /** * Constructor - the list holder is required. */ - protected ItemAspectListValueModelAdapter(ListValueModel listHolder) { + protected ItemAspectListValueModelAdapter(ListValueModel<? extends E> listHolder) { super(listHolder); - this.counters = new IdentityHashMap(); + this.counters = new IdentityHashMap<E, Counter>(); } /** * Constructor - the collection holder is required. */ - protected ItemAspectListValueModelAdapter(CollectionValueModel collectionHolder) { - this(new CollectionListValueModelAdapter(collectionHolder)); + protected ItemAspectListValueModelAdapter(CollectionValueModel<? extends E> collectionHolder) { + this(new CollectionListValueModelAdapter<E>(collectionHolder)); } // ********** ListValueModel implementation ********** - public ListIterator listIterator() { - return this.listHolder.listIterator(); + public Iterator<E> iterator() { + return this.listIterator(); } - @Override - public Object get(int index) { + public ListIterator<E> listIterator() { + return new ReadOnlyListIterator<E>(this.listHolder.listIterator()); + } + + public E get(int index) { return this.listHolder.get(index); } - @Override public int size() { return this.listHolder.size(); } - @Override public Object[] toArray() { return this.listHolder.toArray(); } @@ -105,15 +108,15 @@ public abstract class ItemAspectListValueModelAdapter this.engageItems(this.listHolder.iterator()); } - protected void engageItems(Iterator stream) { + protected void engageItems(Iterator<? extends E> stream) { while (stream.hasNext()) { this.engageItem(stream.next()); } } - protected void engageItem(Object item) { + protected void engageItem(E item) { // listen to an item only once - Counter counter = (Counter) this.counters.get(item); + Counter counter = this.counters.get(item); if (counter == null) { counter = new Counter(); this.counters.put(item, counter); @@ -140,15 +143,15 @@ public abstract class ItemAspectListValueModelAdapter this.disengageItems(this.listHolder.iterator()); } - protected void disengageItems(Iterator stream) { + protected void disengageItems(Iterator<? extends E> stream) { while (stream.hasNext()) { this.disengageItem(stream.next()); } } - protected void disengageItem(Object item) { + protected void disengageItem(E item) { // stop listening to an item only once - Counter counter = (Counter) this.counters.get(item); + Counter counter = this.counters.get(item); if (counter == null) { // something is wrong if this happens... ~bjv throw new IllegalStateException("missing counter: " + item); @@ -175,7 +178,7 @@ public abstract class ItemAspectListValueModelAdapter protected void itemsAdded(ListChangeEvent e) { // re-fire event with the wrapper as the source this.fireItemsAdded(e.cloneWithSource(this, LIST_VALUES)); - this.engageItems(e.items()); + this.engageItems(this.items(e)); } /** @@ -184,7 +187,7 @@ public abstract class ItemAspectListValueModelAdapter */ @Override protected void itemsRemoved(ListChangeEvent e) { - this.disengageItems(e.items()); + this.disengageItems(this.items(e)); // re-fire event with the wrapper as the source this.fireItemsRemoved(e.cloneWithSource(this, LIST_VALUES)); } @@ -196,10 +199,10 @@ public abstract class ItemAspectListValueModelAdapter */ @Override protected void itemsReplaced(ListChangeEvent e) { - this.disengageItems(e.replacedItems()); + this.disengageItems(this.replacedItems(e)); // re-fire event with the wrapper as the source this.fireItemsReplaced(e.cloneWithSource(this, LIST_VALUES)); - this.engageItems(e.items()); + this.engageItems(this.items(e)); } /** @@ -220,7 +223,7 @@ public abstract class ItemAspectListValueModelAdapter protected void listCleared(ListChangeEvent e) { // we should only need to disengage each item once... // make a copy to prevent a ConcurrentModificationException - Collection keys = new ArrayList(this.counters.keySet()); + Collection<E> keys = new ArrayList<E>(this.counters.keySet()); this.disengageItems(keys.iterator()); this.counters.clear(); // re-fire event with the wrapper as the source @@ -235,7 +238,7 @@ public abstract class ItemAspectListValueModelAdapter protected void listChanged(ListChangeEvent e) { // we should only need to disengage each item once... // make a copy to prevent a ConcurrentModificationException - Collection keys = new ArrayList(this.counters.keySet()); + Collection<E> keys = new ArrayList<E>(this.counters.keySet()); this.disengageItems(keys.iterator()); this.counters.clear(); // re-fire event with the wrapper as the source diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemCollectionListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemCollectionListValueModelAdapter.java index 2c114334e9..6157a6a3e0 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemCollectionListValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemCollectionListValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -19,8 +19,8 @@ import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; * Extend ItemAspectListValueModelAdapter to listen to one or more collection * aspects of each item in the wrapped list model. */ -public class ItemCollectionListValueModelAdapter - extends ItemAspectListValueModelAdapter +public class ItemCollectionListValueModelAdapter<E> + extends ItemAspectListValueModelAdapter<E> { /** The names of the items' collections that we listen to. */ @@ -33,30 +33,9 @@ public class ItemCollectionListValueModelAdapter // ********** constructors ********** /** - * Construct an adapter for the specified item Collection. - */ - public ItemCollectionListValueModelAdapter(ListValueModel listHolder, String collectionName) { - this(listHolder, new String[] {collectionName}); - } - - /** * Construct an adapter for the specified item Collections. */ - public ItemCollectionListValueModelAdapter(ListValueModel listHolder, String collectionName1, String collectionName2) { - this(listHolder, new String[] {collectionName1, collectionName2}); - } - - /** - * Construct an adapter for the specified item Collections. - */ - public ItemCollectionListValueModelAdapter(ListValueModel listHolder, String collectionName1, String collectionName2, String collectionName3) { - this(listHolder, new String[] {collectionName1, collectionName2, collectionName3}); - } - - /** - * Construct an adapter for the specified item Collections. - */ - public ItemCollectionListValueModelAdapter(ListValueModel listHolder, String[] collectionNames) { + public ItemCollectionListValueModelAdapter(ListValueModel<E> listHolder, String... collectionNames) { super(listHolder); this.collectionNames = collectionNames; this.itemCollectionListener = this.buildItemCollectionListener(); @@ -65,29 +44,8 @@ public class ItemCollectionListValueModelAdapter /** * Construct an adapter for the specified item Collections. */ - public ItemCollectionListValueModelAdapter(CollectionValueModel collectionHolder, String collectionName) { - this(collectionHolder, new String[] {collectionName}); - } - - /** - * Construct an adapter for the specified item Collections. - */ - public ItemCollectionListValueModelAdapter(CollectionValueModel collectionHolder, String collectionName1, String collectionName2) { - this(collectionHolder, new String[] {collectionName1, collectionName2}); - } - - /** - * Construct an adapter for the specified item Collections. - */ - public ItemCollectionListValueModelAdapter(CollectionValueModel collectionHolder, String collectionName1, String collectionName2, String collectionName3) { - this(collectionHolder, new String[] {collectionName1, collectionName2, collectionName3}); - } - - /** - * Construct an adapter for the specified item Collections. - */ - public ItemCollectionListValueModelAdapter(CollectionValueModel collectionHolder, String[] collectionNames) { - this(new CollectionListValueModelAdapter(collectionHolder), collectionNames); + public ItemCollectionListValueModelAdapter(CollectionValueModel<E> collectionHolder, String... collectionNames) { + this(new CollectionListValueModelAdapter<E>(collectionHolder), collectionNames); } @@ -123,15 +81,15 @@ public class ItemCollectionListValueModelAdapter @Override protected void startListeningToItem(Model item) { - for (int i = this.collectionNames.length; i-- > 0; ) { - item.addCollectionChangeListener(this.collectionNames[i], this.itemCollectionListener); + for (String collectionName : this.collectionNames) { + item.addCollectionChangeListener(collectionName, this.itemCollectionListener); } } @Override protected void stopListeningToItem(Model item) { - for (int i = this.collectionNames.length; i-- > 0; ) { - item.removeCollectionChangeListener(this.collectionNames[i], this.itemCollectionListener); + for (String collectionName : this.collectionNames) { + item.removeCollectionChangeListener(collectionName, this.itemCollectionListener); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemListListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemListListValueModelAdapter.java index d743f54982..e6174055bd 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemListListValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemListListValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -19,8 +19,8 @@ import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; * Extend ItemAspectListValueModelAdapter to listen to one or more list * aspects of each item in the wrapped list model. */ -public class ItemListListValueModelAdapter - extends ItemAspectListValueModelAdapter +public class ItemListListValueModelAdapter<E> + extends ItemAspectListValueModelAdapter<E> { /** The names of the subject's lists that we listen to. */ @@ -33,61 +33,19 @@ public class ItemListListValueModelAdapter // ********** constructors ********** /** - * Construct an adapter for the specified item List aspect. - */ - public ItemListListValueModelAdapter(ListValueModel listHolder, String listName) { - this(listHolder, new String[] {listName}); - } - - /** - * Construct an adapter for the specified item List aspects. - */ - public ItemListListValueModelAdapter(ListValueModel listHolder, String listName1, String listName2) { - this(listHolder, new String[] {listName1, listName2}); - } - - /** - * Construct an adapter for the specified item List aspects. - */ - public ItemListListValueModelAdapter(ListValueModel listHolder, String listName1, String listName2, String listName3) { - this(listHolder, new String[] {listName1, listName2, listName3}); - } - - /** * Construct an adapter for the specified item List aspects. */ - public ItemListListValueModelAdapter(ListValueModel listHolder, String[] listNames) { + public ItemListListValueModelAdapter(ListValueModel<E> listHolder, String... listNames) { super(listHolder); this.listNames = listNames; this.itemListListener = this.buildItemListListener(); } /** - * Construct an adapter for the specified item List aspect. - */ - public ItemListListValueModelAdapter(CollectionValueModel collectionHolder, String listName) { - this(collectionHolder, new String[] {listName}); - } - - /** - * Construct an adapter for the specified item List aspects. - */ - public ItemListListValueModelAdapter(CollectionValueModel collectionHolder, String listName1, String listName2) { - this(collectionHolder, new String[] {listName1, listName2}); - } - - /** - * Construct an adapter for the specified item List aspects. - */ - public ItemListListValueModelAdapter(CollectionValueModel collectionHolder, String listName1, String listName2, String listName3) { - this(collectionHolder, new String[] {listName1, listName2, listName3}); - } - - /** * Construct an adapter for the specified item List aspects. */ - public ItemListListValueModelAdapter(CollectionValueModel collectionHolder, String[] listNames) { - this(new CollectionListValueModelAdapter(collectionHolder), listNames); + public ItemListListValueModelAdapter(CollectionValueModel<E> collectionHolder, String... listNames) { + this(new CollectionListValueModelAdapter<E>(collectionHolder), listNames); } @@ -129,15 +87,15 @@ public class ItemListListValueModelAdapter @Override protected void startListeningToItem(Model item) { - for (int i = this.listNames.length; i-- > 0; ) { - item.addListChangeListener(this.listNames[i], this.itemListListener); + for (String listName : this.listNames) { + item.addListChangeListener(listName, this.itemListListener); } } @Override protected void stopListeningToItem(Model item) { - for (int i = this.listNames.length; i-- > 0; ) { - item.removeListChangeListener(this.listNames[i], this.itemListListener); + for (String listName : this.listNames) { + item.removeListChangeListener(listName, this.itemListListener); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemPropertyListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemPropertyListValueModelAdapter.java index 0a19623f30..9ec52ca98d 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemPropertyListValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemPropertyListValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -19,8 +19,8 @@ import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; * Extend ItemAspectListValueModelAdapter to listen to one or more * properties of each item in the wrapped list model. */ -public class ItemPropertyListValueModelAdapter - extends ItemAspectListValueModelAdapter +public class ItemPropertyListValueModelAdapter<E> + extends ItemAspectListValueModelAdapter<E> { /** The names of the items' properties that we listen to. */ @@ -33,61 +33,19 @@ public class ItemPropertyListValueModelAdapter // ********** constructors ********** /** - * Construct an adapter for the specified item property. - */ - public ItemPropertyListValueModelAdapter(ListValueModel listHolder, String propertyName) { - this(listHolder, new String[] {propertyName}); - } - - /** - * Construct an adapter for the specified item properties. - */ - public ItemPropertyListValueModelAdapter(ListValueModel listHolder, String propertyName1, String propertyName2) { - this(listHolder, new String[] {propertyName1, propertyName2}); - } - - /** - * Construct an adapter for the specified item properties. - */ - public ItemPropertyListValueModelAdapter(ListValueModel listHolder, String propertyName1, String propertyName2, String propertyName3) { - this(listHolder, new String[] {propertyName1, propertyName2, propertyName3}); - } - - /** * Construct an adapter for the specified item properties. */ - public ItemPropertyListValueModelAdapter(ListValueModel listHolder, String[] propertyNames) { + public ItemPropertyListValueModelAdapter(ListValueModel<E> listHolder, String... propertyNames) { super(listHolder); this.propertyNames = propertyNames; this.itemPropertyListener = this.buildItemPropertyListener(); } /** - * Construct an adapter for the specified item property. - */ - public ItemPropertyListValueModelAdapter(CollectionValueModel collectionHolder, String propertyName) { - this(collectionHolder, new String[] {propertyName}); - } - - /** - * Construct an adapter for the specified item properties. - */ - public ItemPropertyListValueModelAdapter(CollectionValueModel collectionHolder, String propertyName1, String propertyName2) { - this(collectionHolder, new String[] {propertyName1, propertyName2}); - } - - /** - * Construct an adapter for the specified item properties. - */ - public ItemPropertyListValueModelAdapter(CollectionValueModel collectionHolder, String propertyName1, String propertyName2, String propertyName3) { - this(collectionHolder, new String[] {propertyName1, propertyName2, propertyName3}); - } - - /** * Construct an adapter for the specified item properties. */ - public ItemPropertyListValueModelAdapter(CollectionValueModel collectionHolder, String[] propertyNames) { - this(new CollectionListValueModelAdapter(collectionHolder), propertyNames); + public ItemPropertyListValueModelAdapter(CollectionValueModel<E> collectionHolder, String... propertyNames) { + this(new CollectionListValueModelAdapter<E>(collectionHolder), propertyNames); } @@ -110,15 +68,15 @@ public class ItemPropertyListValueModelAdapter @Override protected void startListeningToItem(Model item) { - for (int i = this.propertyNames.length; i-- > 0; ) { - item.addPropertyChangeListener(this.propertyNames[i], this.itemPropertyListener); + for (String propertyName : this.propertyNames) { + item.addPropertyChangeListener(propertyName, this.itemPropertyListener); } } @Override protected void stopListeningToItem(Model item) { - for (int i = this.propertyNames.length; i-- > 0; ) { - item.removePropertyChangeListener(this.propertyNames[i], this.itemPropertyListener); + for (String propertyName : this.propertyNames) { + item.removePropertyChangeListener(propertyName, this.itemPropertyListener); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemStateListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemStateListValueModelAdapter.java index 9548fbb37e..50c1a52c46 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemStateListValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemStateListValueModelAdapter.java @@ -17,8 +17,8 @@ import org.eclipse.jpt.utility.internal.model.listener.StateChangeListener; * Extend ItemAspectListValueModelAdapter to listen to the * "state" of each item in the wrapped list model. */ -public class ItemStateListValueModelAdapter - extends ItemAspectListValueModelAdapter +public class ItemStateListValueModelAdapter<E> + extends ItemAspectListValueModelAdapter<E> { /** Listener that listens to all the items in the list. */ protected final StateChangeListener itemStateListener; @@ -29,7 +29,7 @@ public class ItemStateListValueModelAdapter /** * Construct an adapter for the item state. */ - public ItemStateListValueModelAdapter(ListValueModel listHolder) { + public ItemStateListValueModelAdapter(ListValueModel<E> listHolder) { super(listHolder); this.itemStateListener = this.buildItemStateListener(); } @@ -37,8 +37,8 @@ public class ItemStateListValueModelAdapter /** * Construct an adapter for the item state. */ - public ItemStateListValueModelAdapter(CollectionValueModel collectionHolder) { - this(new CollectionListValueModelAdapter(collectionHolder)); + public ItemStateListValueModelAdapter(CollectionValueModel<E> collectionHolder) { + this(new CollectionListValueModelAdapter<E>(collectionHolder)); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemTreeListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemTreeListValueModelAdapter.java new file mode 100644 index 0000000000..86ec2f5b89 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemTreeListValueModelAdapter.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Arrays; + +import org.eclipse.jpt.utility.internal.model.Model; +import org.eclipse.jpt.utility.internal.model.event.TreeChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.TreeChangeListener; + +/** + * Extend ItemAspectListValueModelAdapter to listen to one or more tree + * aspects of each item in the wrapped list model. + */ +public class ItemTreeListValueModelAdapter<E> + extends ItemAspectListValueModelAdapter<E> +{ + + /** The names of the items' tree that we listen to. */ + protected final String[] treeNames; + + /** Listener that listens to all the items in the list. */ + protected final TreeChangeListener itemTreeListener; + + + // ********** constructors ********** + + /** + * Construct an adapter for the specified item trees. + */ + public ItemTreeListValueModelAdapter(ListValueModel<E> listHolder, String... treeNames) { + super(listHolder); + this.treeNames = treeNames; + this.itemTreeListener = this.buildItemTreeListener(); + } + + /** + * Construct an adapter for the specified item trees. + */ + public ItemTreeListValueModelAdapter(CollectionValueModel<E> collectionHolder, String... treeNames) { + this(new CollectionListValueModelAdapter<E>(collectionHolder), treeNames); + } + + + // ********** initialization ********** + + /** + * All we really care about is the fact that a tree aspect has + * changed. Do the same thing no matter which event occurs. + */ + protected TreeChangeListener buildItemTreeListener() { + return new TreeChangeListener() { + public void nodeAdded(TreeChangeEvent e) { + ItemTreeListValueModelAdapter.this.itemAspectChanged(e); + } + public void nodeRemoved(TreeChangeEvent e) { + ItemTreeListValueModelAdapter.this.itemAspectChanged(e); + } + public void treeCleared(TreeChangeEvent e) { + ItemTreeListValueModelAdapter.this.itemAspectChanged(e); + } + public void treeChanged(TreeChangeEvent e) { + ItemTreeListValueModelAdapter.this.itemAspectChanged(e); + } + @Override + public String toString() { + return "item tree listener: " + Arrays.asList(ItemTreeListValueModelAdapter.this.treeNames); + } + }; + } + + + // ********** behavior ********** + + @Override + protected void startListeningToItem(Model item) { + for (String treeName : this.treeNames) { + item.addTreeChangeListener(treeName, this.itemTreeListener); + } + } + + @Override + protected void stopListeningToItem(Model item) { + for (String treeName : this.treeNames) { + item.removeTreeChangeListener(treeName, this.itemTreeListener); + } + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListAspectAdapter.java index 3d4981bf85..fc94f933cb 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListAspectAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListAspectAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,6 +9,8 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; +import java.util.Arrays; +import java.util.Collection; import java.util.Iterator; import java.util.ListIterator; @@ -21,6 +23,8 @@ import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; /** * This extension of AspectAdapter provides ListChange support. + * This allows us to convert a set of one or more collections into + * a single collection, LIST_VALUES. * * The typical subclass will override the following methods: * #listIterator_() @@ -39,14 +43,15 @@ import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; * override this method only if returning a zero when the * subject is null is unacceptable */ -public abstract class ListAspectAdapter - extends AspectAdapter - implements ListValueModel +public abstract class ListAspectAdapter<S extends Model, E> + extends AspectAdapter<S> + implements ListValueModel<E> { /** - * The name of the subject's list that we use for the value. + * The name of the subject's lists that we use for the value. */ - protected final String listName; + protected final String[] listNames; + protected static final String[] EMPTY_LIST_NAMES = new String[0]; /** A listener that listens to the subject's list aspect. */ protected final ListChangeListener listChangeListener; @@ -60,30 +65,46 @@ public abstract class ListAspectAdapter * Construct a ListAspectAdapter for the specified subject * and list. */ - protected ListAspectAdapter(String listName, Model subject) { - this(new ReadOnlyPropertyValueModel(subject), listName); + protected ListAspectAdapter(String listName, S subject) { + this(new String[] {listName}, subject); } /** - * Construct a ListAspectAdapter for an "unchanging" list in - * the specified subject. This is useful for a list aspect that does not - * change for a particular subject; but the subject will change, resulting in - * a new list. + * Construct a ListAspectAdapter for the specified subject + * and lists. */ - protected ListAspectAdapter(ValueModel subjectHolder) { - this(subjectHolder, null); + protected ListAspectAdapter(String[] listNames, S subject) { + this(new StaticPropertyValueModel<S>(subject), listNames); } /** * Construct a ListAspectAdapter for the specified subject holder - * and list. + * and lists. */ - protected ListAspectAdapter(ValueModel subjectHolder, String listName) { + protected ListAspectAdapter(PropertyValueModel<? extends S> subjectHolder, String... listNames) { super(subjectHolder); - this.listName = listName; + this.listNames = listNames; this.listChangeListener = this.buildListChangeListener(); } + /** + * Construct a ListAspectAdapter for the specified subject holder + * and lists. + */ + protected ListAspectAdapter(PropertyValueModel<? extends S> subjectHolder, Collection<String> listNames) { + this(subjectHolder, listNames.toArray(new String[listNames.size()])); + } + + /** + * Construct a ListAspectAdapter for an "unchanging" list in + * the specified subject. This is useful for a list aspect that does not + * change for a particular subject; but the subject will change, resulting in + * a new list. + */ + protected ListAspectAdapter(PropertyValueModel<? extends S> subjectHolder) { + this(subjectHolder, EMPTY_LIST_NAMES); + } + // ********** initialization ********** @@ -113,7 +134,7 @@ public abstract class ListAspectAdapter } @Override public String toString() { - return "list change listener: " + ListAspectAdapter.this.listName; + return "list change listener: " + Arrays.asList(ListAspectAdapter.this.listNames); } }; } @@ -124,15 +145,15 @@ public abstract class ListAspectAdapter /** * Return the elements of the subject's list aspect. */ - public Iterator iterator() { + public Iterator<E> iterator() { return this.listIterator(); } /** * Return the elements of the subject's list aspect. */ - public ListIterator listIterator() { - return (this.subject == null) ? EmptyListIterator.instance() : this.listIterator_(); + public ListIterator<E> listIterator() { + return (this.subject == null) ? EmptyListIterator.<E>instance() : this.listIterator_(); } /** @@ -140,14 +161,14 @@ public abstract class ListAspectAdapter * At this point we can be sure that the subject is not null. * @see #listIterator() */ - protected ListIterator listIterator_() { + protected ListIterator<E> listIterator_() { throw new UnsupportedOperationException(); } /** * Return the element at the specified index of the subject's list aspect. */ - public Object get(int index) { + public E get(int index) { return CollectionTools.get(this.listIterator(), index); } @@ -212,22 +233,27 @@ public abstract class ListAspectAdapter } @Override - protected void engageNonNullSubject() { - if (this.listName != null) { - ((Model) this.subject).addListChangeListener(this.listName, this.listChangeListener); + protected void engageSubject_() { + for (String listName : this.listNames) { + ((Model) this.subject).addListChangeListener(listName, this.listChangeListener); } } @Override - protected void disengageNonNullSubject() { - if (this.listName != null) { - ((Model) this.subject).removeListChangeListener(this.listName, this.listChangeListener); + protected void disengageSubject_() { + for (String listName : this.listNames) { + ((Model) this.subject).removeListChangeListener(listName, this.listChangeListener); } } @Override public void toString(StringBuilder sb) { - sb.append(this.listName); + for (int i = 0; i < this.listNames.length; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(this.listNames[i]); + } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCollectionValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCollectionValueModelAdapter.java index 0492a43f1c..42eab093f3 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCollectionValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCollectionValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -10,8 +10,8 @@ package org.eclipse.jpt.utility.internal.model.value; import java.util.ArrayList; -import java.util.Collection; import java.util.Iterator; +import java.util.ListIterator; import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator; import org.eclipse.jpt.utility.internal.model.AbstractModel; @@ -34,12 +34,12 @@ import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; * we do not have any listeners. This should not be too painful since, * most likely, client objects will also be listeners. */ -public class ListCollectionValueModelAdapter +public class ListCollectionValueModelAdapter<E> extends AbstractModel - implements CollectionValueModel + implements CollectionValueModel<E> { /** The wrapped list value model. */ - protected final ListValueModel listHolder; + protected final ListValueModel<? extends E> listHolder; /** A listener that forwards any events fired by the list holder. */ protected final ListChangeListener listChangeListener; @@ -49,7 +49,7 @@ public class ListCollectionValueModelAdapter * the wrapped list. */ // we declare this an ArrayList so we can use #clone() and #ensureCapacity(int) - protected final ArrayList collection; + protected final ArrayList<E> collection; // ********** constructors/initialization ********** @@ -57,14 +57,14 @@ public class ListCollectionValueModelAdapter /** * Wrap the specified ListValueModel. */ - public ListCollectionValueModelAdapter(ListValueModel listHolder) { + public ListCollectionValueModelAdapter(ListValueModel<? extends E> listHolder) { super(); if (listHolder == null) { throw new NullPointerException(); } this.listHolder = listHolder; this.listChangeListener = this.buildListChangeListener(); - this.collection = new ArrayList(); + this.collection = new ArrayList<E>(); // postpone building the collection and listening to the underlying list // until we have listeners ourselves... } @@ -108,9 +108,9 @@ public class ListCollectionValueModelAdapter // ********** CollectionValueModel implementation ********** - public Iterator iterator() { + public Iterator<E> iterator() { // try to prevent backdoor modification of the list - return new ReadOnlyIterator(this.collection); + return new ReadOnlyIterator<E>(this.collection); } public int size() { @@ -200,7 +200,7 @@ public class ListCollectionValueModelAdapter // ********** behavior ********** protected void buildCollection() { - Iterator stream = this.listHolder.iterator(); + Iterator<? extends E> stream = this.listHolder.iterator(); // if the new list is empty, do nothing if (stream.hasNext()) { this.collection.ensureCapacity(this.listHolder.size()); @@ -223,11 +223,23 @@ public class ListCollectionValueModelAdapter this.collection.clear(); } + // minimize suppressed warnings + @SuppressWarnings("unchecked") + protected ListIterator<E> items(ListChangeEvent e) { + return (ListIterator<E>) e.items(); + } + + // minimize suppressed warnings + @SuppressWarnings("unchecked") + protected ListIterator<E> replacedItems(ListChangeEvent e) { + return (ListIterator<E>) e.replacedItems(); + } + protected void itemsAdded(ListChangeEvent e) { - this.addItemsToCollection(e.items(), this.collection, VALUES); + this.addItemsToCollection(this.items(e), this.collection, VALUES); } - protected void removeInternalItems(Iterator items) { + protected void removeInternalItems(Iterator<E> items) { // we have to remove the items individually, // since they are probably not in sequence while (items.hasNext()) { @@ -239,12 +251,12 @@ public class ListCollectionValueModelAdapter } protected void itemsRemoved(ListChangeEvent e) { - this.removeInternalItems(e.items()); + this.removeInternalItems(this.items(e)); } protected void itemsReplaced(ListChangeEvent e) { - this.removeInternalItems(e.replacedItems()); - this.addItemsToCollection(e.items(), this.collection, VALUES); + this.removeInternalItems(this.replacedItems(e)); + this.addItemsToCollection(this.items(e), this.collection, VALUES); } protected void itemsMoved(ListChangeEvent e) { @@ -266,7 +278,8 @@ public class ListCollectionValueModelAdapter protected void listChanged(ListChangeEvent e) { // put in empty check so we don't fire events unnecessarily if ( ! this.collection.isEmpty()) { - ArrayList removedItems = (ArrayList) this.collection.clone(); + @SuppressWarnings("unchecked") + ArrayList<E> removedItems = (ArrayList<E>) this.collection.clone(); this.collection.clear(); this.fireItemsRemoved(VALUES, removedItems); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCurator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCurator.java index 0b6d6d2567..900b5d5635 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCurator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCurator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -27,12 +27,12 @@ import org.eclipse.jpt.utility.internal.model.listener.StateChangeListener; * by adapting a subject's state change events to a minimum set * of list change events. */ -public abstract class ListCurator - extends AspectAdapter - implements ListValueModel +public abstract class ListCurator<S extends Model, E> + extends AspectAdapter<S> + implements ListValueModel<E> { /** How the list looked before the last state change */ - private final ArrayList record; + private final ArrayList<E> record; /** A listener that listens for the subject's state to change */ private final StateChangeListener stateChangeListener; @@ -43,17 +43,17 @@ public abstract class ListCurator /** * Construct a Curator for the specified subject. */ - protected ListCurator(Model subject) { - this(new ReadOnlyPropertyValueModel(subject)); + protected ListCurator(S subject) { + this(new StaticPropertyValueModel<S>(subject)); } /** * Construct a curator for the specified subject holder. * The subject holder cannot be null. */ - protected ListCurator(ValueModel subjectHolder) { + protected ListCurator(PropertyValueModel<? extends S> subjectHolder) { super(subjectHolder); - this.record = new ArrayList(); + this.record = new ArrayList<E>(); this.stateChangeListener = this.buildStateChangeListener(); } @@ -78,18 +78,18 @@ public abstract class ListCurator // ********** ListValueModel implementation ********** - public Iterator iterator() { + public Iterator<E> iterator() { return this.listIterator(); } - public ListIterator listIterator() { - return new ReadOnlyListIterator(this.record); + public ListIterator<E> listIterator() { + return new ReadOnlyListIterator<E>(this.record); } /** * Return the item at the specified index of the subject's list aspect. */ - public Object get(int index) { + public E get(int index) { return this.record.get(index); } @@ -142,7 +142,7 @@ public abstract class ListCurator * The subject is not null - add our listener. */ @Override - protected void engageNonNullSubject() { + protected void engageSubject_() { ((Model) this.subject).addStateChangeListener(this.stateChangeListener); // synch our list *after* we start listening to the subject, // since its value might change when a listener is added @@ -153,7 +153,7 @@ public abstract class ListCurator * The subject is not null - remove our listener. */ @Override - protected void disengageNonNullSubject() { + protected void disengageSubject_() { ((Model) this.subject).removeStateChangeListener(this.stateChangeListener); // clear out the list when we are not listening to the subject this.record.clear(); @@ -167,24 +167,24 @@ public abstract class ListCurator * It is intended to be used only when the subject changes or the * subject's "state" changes (as signified by a state change event). */ - protected abstract Iterator iteratorForRecord(); + protected abstract Iterator<E> iteratorForRecord(); // ********** behavior ********** void submitInventoryReport() { - List newRecord = CollectionTools.list(this.iteratorForRecord()); + List<E> newRecord = CollectionTools.list(this.iteratorForRecord()); int recordIndex = 0; // add items from the new record - for (Object newItem : newRecord) { + for (E newItem : newRecord) { this.inventoryNewItem(recordIndex, newItem); recordIndex++; } // clean out items that are no longer in the new record for (recordIndex = 0; recordIndex < this.record.size(); ) { - Object item = this.record.get(recordIndex); + E item = this.record.get(recordIndex); if (newRecord.contains(item)) { recordIndex++; @@ -194,8 +194,8 @@ public abstract class ListCurator } } - private void inventoryNewItem(int recordIndex, Object newItem) { - List rec = new ArrayList(this.record); + private void inventoryNewItem(int recordIndex, E newItem) { + List<E> rec = new ArrayList<E>(this.record); if ((recordIndex < rec.size()) && rec.get(recordIndex).equals(newItem)) { return; @@ -208,11 +208,11 @@ public abstract class ListCurator } } - private void addItemToInventory(int index, Object item) { + private void addItemToInventory(int index, E item) { this.addItemToList(index, item, this.record, LIST_VALUES); } - private void removeItemFromInventory(int index, Object item) { + private void removeItemFromInventory(int index, E item) { this.removeItemFromList(index, this.record, LIST_VALUES); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListPropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListPropertyValueModelAdapter.java new file mode 100644 index 0000000000..5d7d4ccc1b --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListPropertyValueModelAdapter.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.model.event.ListChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; + +/** + * This abstract class provides the infrastructure needed to wrap + * a list value model, "lazily" listen to it, and convert + * its change notifications into property value model change + * notifications. + * + * Subclasses must override: + * - #buildValue() + * to return the current property value, as derived from the + * current list value + * + * Subclasses might want to override: + * - #itemsAdded(ListChangeEvent e) + * - #itemsRemoved(ListChangeEvent e) + * - #itemsReplaced(ListChangeEvent e) + * - #itemsMoved(ListChangeEvent e) + * - #listCleared(ListChangeEvent e) + * - #listChanged(ListChangeEvent e) + * to improve performance (by not recalculating the value, if possible) + */ +public abstract class ListPropertyValueModelAdapter<T> + extends AspectPropertyValueModelAdapter<T> +{ + /** The wrapped list value model. */ + protected final ListValueModel<?> listHolder; + + /** A listener that allows us to synch with changes to the wrapped list holder. */ + protected final ListChangeListener listChangeListener; + + + // ********** constructor/initialization ********** + + /** + * Construct a property value model with the specified wrapped + * list value model. + */ + protected ListPropertyValueModelAdapter(ListValueModel<?> listHolder) { + super(); + this.listHolder = listHolder; + this.listChangeListener = this.buildListChangeListener(); + } + + protected ListChangeListener buildListChangeListener() { + return new ListChangeListener() { + public void itemsAdded(ListChangeEvent e) { + ListPropertyValueModelAdapter.this.itemsAdded(e); + } + public void itemsRemoved(ListChangeEvent e) { + ListPropertyValueModelAdapter.this.itemsRemoved(e); + } + public void itemsReplaced(ListChangeEvent e) { + ListPropertyValueModelAdapter.this.itemsReplaced(e); + } + public void itemsMoved(ListChangeEvent e) { + ListPropertyValueModelAdapter.this.itemsMoved(e); + } + public void listCleared(ListChangeEvent e) { + ListPropertyValueModelAdapter.this.listCleared(e); + } + public void listChanged(ListChangeEvent e) { + ListPropertyValueModelAdapter.this.listChanged(e); + } + @Override + public String toString() { + return "list change listener"; + } + }; + } + + + // ********** behavior ********** + + /** + * Start listening to the list holder. + */ + @Override + protected void engageModel_() { + this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener); + } + + /** + * Stop listening to the list holder. + */ + @Override + protected void disengageModel_() { + this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.listHolder); + } + + + // ********** collection change support ********** + + /** + * Items were added to the wrapped list holder; + * propagate the change notification appropriately. + */ + protected void itemsAdded(ListChangeEvent e) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + + /** + * Items were removed from the wrapped list holder; + * propagate the change notification appropriately. + */ + protected void itemsRemoved(ListChangeEvent e) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + + /** + * Items were replaced in the wrapped list holder; + * propagate the change notification appropriately. + */ + protected void itemsReplaced(ListChangeEvent e) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + + /** + * Items were moved in the wrapped list holder; + * propagate the change notification appropriately. + */ + protected void itemsMoved(ListChangeEvent e) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + + /** + * The wrapped list holder was cleared; + * propagate the change notification appropriately. + */ + protected void listCleared(ListChangeEvent e) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + + /** + * The value of the wrapped list holder has changed; + * propagate the change notification appropriately. + */ + protected void listChanged(ListChangeEvent e) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModel.java index d432922aa8..33fda0c2be 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -18,19 +18,19 @@ import org.eclipse.jpt.utility.internal.model.Model; * Interface used to abstract list accessing and * change notification and make it more pluggable. */ -public interface ListValueModel - extends Model//, Iterable<E> +public interface ListValueModel<E> + extends Model, Iterable<E> { /** * Return the list's values. */ - Iterator iterator(); + Iterator<E> iterator(); String LIST_VALUES = "list values"; /** * Return the list's values. */ - ListIterator listIterator(); + ListIterator<E> listIterator(); /** * Return the size of the list. @@ -40,7 +40,7 @@ public interface ListValueModel /** * Return the item at the specified index of the list. */ - Object get(int index); + E get(int index); /** * Return the list's values. diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModelWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModelWrapper.java index f97920c3db..3c09087e12 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModelWrapper.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModelWrapper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,9 +9,8 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; -import java.util.Iterator; +import java.util.ListIterator; -import org.eclipse.jpt.utility.internal.CollectionTools; import org.eclipse.jpt.utility.internal.model.AbstractModel; import org.eclipse.jpt.utility.internal.model.ChangeSupport; import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport; @@ -23,13 +22,12 @@ import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; * another list value model, "lazily" listen to it, and propagate * its change notifications. */ -public abstract class ListValueModelWrapper +public abstract class ListValueModelWrapper<E> extends AbstractModel - implements ListValueModel { /** The wrapped list value model. */ - protected final ListValueModel listHolder; + protected final ListValueModel<? extends E> listHolder; /** A listener that allows us to synch with changes to the wrapped list holder. */ protected final ListChangeListener listChangeListener; @@ -41,7 +39,7 @@ public abstract class ListValueModelWrapper * Construct a list value model with the specified wrapped * list value model. */ - protected ListValueModelWrapper(ListValueModel listHolder) { + protected ListValueModelWrapper(ListValueModel<? extends E> listHolder) { super(); if (listHolder == null) { throw new NullPointerException(); @@ -55,7 +53,7 @@ public abstract class ListValueModelWrapper @Override protected ChangeSupport buildChangeSupport() { - return new SingleAspectChangeSupport(this, ListChangeListener.class, LIST_VALUES); + return new SingleAspectChangeSupport(this, ListChangeListener.class, ListValueModel.LIST_VALUES); } protected ListChangeListener buildListChangeListener() { @@ -86,25 +84,6 @@ public abstract class ListValueModelWrapper } - // ********** ListValueModel implementation ********** - - public Iterator iterator() { - return this.listIterator(); - } - - public Object get(int index) { - return CollectionTools.get(this.listIterator(), index); - } - - public int size() { - return CollectionTools.size(this.listIterator()); - } - - public Object[] toArray() { - return CollectionTools.array(this.listIterator()); - } - - // ********** extend change support ********** /** @@ -112,7 +91,7 @@ public abstract class ListValueModelWrapper */ @Override public synchronized void addListChangeListener(ListChangeListener listener) { - if (this.hasNoListChangeListeners(LIST_VALUES)) { + if (this.hasNoListChangeListeners(ListValueModel.LIST_VALUES)) { this.engageModel(); } super.addListChangeListener(listener); @@ -123,7 +102,7 @@ public abstract class ListValueModelWrapper */ @Override public synchronized void addListChangeListener(String listName, ListChangeListener listener) { - if (listName == LIST_VALUES && this.hasNoListChangeListeners(LIST_VALUES)) { + if (listName == ListValueModel.LIST_VALUES && this.hasNoListChangeListeners(ListValueModel.LIST_VALUES)) { this.engageModel(); } super.addListChangeListener(listName, listener); @@ -135,7 +114,7 @@ public abstract class ListValueModelWrapper @Override public synchronized void removeListChangeListener(ListChangeListener listener) { super.removeListChangeListener(listener); - if (this.hasNoListChangeListeners(LIST_VALUES)) { + if (this.hasNoListChangeListeners(ListValueModel.LIST_VALUES)) { this.disengageModel(); } } @@ -146,7 +125,7 @@ public abstract class ListValueModelWrapper @Override public synchronized void removeListChangeListener(String listName, ListChangeListener listener) { super.removeListChangeListener(listName, listener); - if (listName == LIST_VALUES && this.hasNoListChangeListeners(LIST_VALUES)) { + if (listName == ListValueModel.LIST_VALUES && this.hasNoListChangeListeners(ListValueModel.LIST_VALUES)) { this.disengageModel(); } } @@ -158,14 +137,14 @@ public abstract class ListValueModelWrapper * Start listening to the list holder. */ protected void engageModel() { - this.listHolder.addListChangeListener(LIST_VALUES, this.listChangeListener); + this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener); } /** * Stop listening to the list holder. */ protected void disengageModel() { - this.listHolder.removeListChangeListener(LIST_VALUES, this.listChangeListener); + this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener); } @Override @@ -173,6 +152,18 @@ public abstract class ListValueModelWrapper sb.append(this.listHolder); } + // minimize suppressed warnings + @SuppressWarnings("unchecked") + protected ListIterator<E> items(ListChangeEvent e) { + return (ListIterator<E>) e.items(); + } + + // minimize suppressed warnings + @SuppressWarnings("unchecked") + protected ListIterator<E> replacedItems(ListChangeEvent e) { + return (ListIterator<E>) e.replacedItems(); + } + // ********** list change support ********** diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullCollectionValueModel.java index 767a915369..a3e8e4cf82 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullCollectionValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullCollectionValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -11,46 +11,39 @@ package org.eclipse.jpt.utility.internal.model.value; import java.util.Iterator; +import org.eclipse.jpt.utility.internal.ClassTools; import org.eclipse.jpt.utility.internal.iterators.EmptyIterator; - +import org.eclipse.jpt.utility.internal.model.AbstractModel; /** * A read-only collection value model for when you * don't need to support a collection. In particular, this * is useful for the leaf nodes of a tree that never have * children. + * + * We don't use a singleton because we hold on to listeners. */ -public final class NullCollectionValueModel - extends AbstractReadOnlyCollectionValueModel +public final class NullCollectionValueModel<E> + extends AbstractModel + implements CollectionValueModel<E> { private static final long serialVersionUID = 1L; - // singleton - private static final NullCollectionValueModel INSTANCE = new NullCollectionValueModel(); - /** - * Return the singleton. + * Default constructor. */ - public static synchronized CollectionValueModel instance() { - return INSTANCE; - } - - /** - * Ensure non-instantiability. - */ - private NullCollectionValueModel() { + public NullCollectionValueModel() { super(); } // ********** CollectionValueModel implementation ********** - @Override public int size() { return 0; } - public Iterator iterator() { + public Iterator<E> iterator() { return EmptyIterator.instance(); } @@ -59,14 +52,7 @@ public final class NullCollectionValueModel @Override public String toString() { - return "NullCollectionValueModel"; - } - - /** - * Serializable singleton support - */ - private Object readResolve() { - return instance(); + return ClassTools.shortClassNameForObject(this); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullListValueModel.java index 14747d6fae..fbfc1ccf65 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullListValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullListValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,52 +9,53 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; +import java.util.Iterator; import java.util.ListIterator; +import org.eclipse.jpt.utility.internal.ClassTools; +import org.eclipse.jpt.utility.internal.iterators.EmptyIterator; import org.eclipse.jpt.utility.internal.iterators.EmptyListIterator; - +import org.eclipse.jpt.utility.internal.model.AbstractModel; /** - * A read-only list value model for when you don't + * An empty list value model for when you don't * need to support a list. + * + * We don't use a singleton because we hold on to listeners. */ -public final class NullListValueModel - extends AbstractReadOnlyListValueModel +public final class NullListValueModel<E> + extends AbstractModel + implements ListValueModel<E> { - private static final Object[] EMPTY_ARRAY = new Object[0]; private static final long serialVersionUID = 1L; - // singleton - private static final NullListValueModel INSTANCE = new NullListValueModel(); - - /** - * Return the singleton. - */ - public static synchronized ListValueModel instance() { - return INSTANCE; - } - /** - * Ensure non-instantiability. + * Default constructor. */ - private NullListValueModel() { + public NullListValueModel() { super(); } // ********** ListValueModel implementation ********** - @Override + public Iterator<E> iterator() { + return EmptyIterator.instance(); + } + + public ListIterator<E> listIterator() { + return EmptyListIterator.instance(); + } + public int size() { return 0; } - public ListIterator listIterator() { - return EmptyListIterator.instance(); + public E get(int index) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: 0"); } - @Override public Object[] toArray() { return EMPTY_ARRAY; } @@ -62,16 +63,9 @@ public final class NullListValueModel // ********** Object overrides ********** - @Override + @Override public String toString() { - return "NullListValueModel"; - } - - /** - * Serializable singleton support - */ - private Object readResolve() { - return instance(); + return ClassTools.shortClassNameForObject(this); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullPropertyValueModel.java index 2df9b11ad4..a69cda1146 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullPropertyValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullPropertyValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,37 +9,32 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; +import org.eclipse.jpt.utility.internal.ClassTools; +import org.eclipse.jpt.utility.internal.model.AbstractModel; + /** - * A read-only property value model for when you + * A property value model for when you * don't need to support a value. + * + * We don't use a singleton because we hold on to listeners. */ -public final class NullPropertyValueModel - extends AbstractReadOnlyPropertyValueModel +public class NullPropertyValueModel<T> + extends AbstractModel + implements PropertyValueModel<T> { - private static final long serialVersionUID = 1L; - // singleton - private static final NullPropertyValueModel INSTANCE = new NullPropertyValueModel(); - - /** - * Return the singleton. - */ - public static synchronized PropertyValueModel instance() { - return INSTANCE; - } - /** - * Ensure non-instantiability. + * Default constructor. */ - private NullPropertyValueModel() { + public NullPropertyValueModel() { super(); } // ********** PropertyValueModel implementation ********** - public Object value() { + public T value() { return null; } @@ -48,14 +43,7 @@ public final class NullPropertyValueModel @Override public String toString() { - return "NullPropertyValueModel"; - } - - /** - * Serializable singleton support - */ - private Object readResolve() { - return instance(); + return ClassTools.shortClassNameForObject(this); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullTreeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullTreeValueModel.java new file mode 100644 index 0000000000..a914e8fb9b --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullTreeValueModel.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Iterator; + +import org.eclipse.jpt.utility.internal.ClassTools; +import org.eclipse.jpt.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.utility.internal.model.AbstractModel; + +/** + * A tree value model for when you + * don't need to support any nodes. + * + * We don't use a singleton because we hold on to listeners. + */ +public class NullTreeValueModel<E> + extends AbstractModel + implements TreeValueModel<E> +{ + private static final long serialVersionUID = 1L; + + /** + * Default constructor. + */ + public NullTreeValueModel() { + super(); + } + + + // ********** TreeValueModel implementation ********** + + public Iterator<E> nodes() { + return EmptyIterator.instance(); + } + + + // ********** Object overrides ********** + + @Override + public String toString() { + return ClassTools.shortClassNameForObject(this); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyAspectAdapter.java index 6f43abb60a..15f00844f1 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyAspectAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyAspectAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -39,9 +39,9 @@ import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; * override this method only if something must be done when the subject * is null (e.g. throw an exception) */ -public abstract class PropertyAspectAdapter - extends AspectAdapter - implements PropertyValueModel +public abstract class PropertyAspectAdapter<S extends Model, T> + extends AspectAdapter<S> + implements WritablePropertyValueModel<T> { /** * Cache the current value of the aspect so we @@ -50,11 +50,11 @@ public abstract class PropertyAspectAdapter * not be in the property change event fired by the subject, * especially when dealing with multiple aspects. */ - protected Object value; + protected T value; /** The name of the subject's properties that we use for the value. */ protected final String[] propertyNames; - private static final String[] EMPTY_PROPERTY_NAMES = new String[0]; + protected static final String[] EMPTY_PROPERTY_NAMES = new String[0]; /** A listener that listens to the appropriate properties of the subject. */ protected final PropertyChangeListener propertyChangeListener; @@ -66,7 +66,7 @@ public abstract class PropertyAspectAdapter * Construct a PropertyAspectAdapter for the specified subject * and property. */ - protected PropertyAspectAdapter(String propertyName, Model subject) { + protected PropertyAspectAdapter(String propertyName, S subject) { this(new String[] {propertyName}, subject); } @@ -74,15 +74,15 @@ public abstract class PropertyAspectAdapter * Construct a PropertyAspectAdapter for the specified subject * and properties. */ - protected PropertyAspectAdapter(String[] propertyNames, Model subject) { - this(new ReadOnlyPropertyValueModel(subject), propertyNames); + protected PropertyAspectAdapter(String[] propertyNames, S subject) { + this(new StaticPropertyValueModel<S>(subject), propertyNames); } /** * Construct a PropertyAspectAdapter for the specified subject holder * and properties. */ - protected PropertyAspectAdapter(ValueModel subjectHolder, String... propertyNames) { + protected PropertyAspectAdapter(PropertyValueModel<? extends S> subjectHolder, String... propertyNames) { super(subjectHolder); this.propertyNames = propertyNames; this.propertyChangeListener = this.buildPropertyChangeListener(); @@ -94,7 +94,7 @@ public abstract class PropertyAspectAdapter * Construct a PropertyAspectAdapter for the specified subject holder * and properties. */ - protected PropertyAspectAdapter(ValueModel subjectHolder, Collection<String> propertyNames) { + protected PropertyAspectAdapter(PropertyValueModel<? extends S> subjectHolder, Collection<String> propertyNames) { this(subjectHolder, propertyNames.toArray(new String[propertyNames.size()])); } @@ -102,9 +102,10 @@ public abstract class PropertyAspectAdapter * Construct a PropertyAspectAdapter for an "unchanging" property in * the specified subject. This is useful for a property aspect that does not * change for a particular subject; but the subject will change, resulting in - * a new property. + * a new property. (A TransformationPropertyValueModel could also be + * used in this situation.) */ - protected PropertyAspectAdapter(ValueModel subjectHolder) { + protected PropertyAspectAdapter(PropertyValueModel<? extends S> subjectHolder) { this(subjectHolder, EMPTY_PROPERTY_NAMES); } @@ -128,23 +129,23 @@ public abstract class PropertyAspectAdapter } - // ********** ValueModel implementation ********** + // ********** PropertyValueModel implementation ********** /** * Return the value of the subject's property. */ @Override - public final Object value() { + public final T value() { return this.value; } - // ********** PropertyValueModel implementation ********** + // ********** WritablePropertyValueModel implementation ********** /** * Set the value of the subject's property. */ - public void setValue(Object value) { + public void setValue(T value) { if (this.subject != null) { this.setValue_(value); } @@ -155,7 +156,7 @@ public abstract class PropertyAspectAdapter * At this point we can be sure that the subject is not null. * @see #setValue(Object) */ - protected void setValue_(Object value) { + protected void setValue_(T value) { throw new UnsupportedOperationException(); } @@ -191,9 +192,9 @@ public abstract class PropertyAspectAdapter } @Override - protected void engageNonNullSubject() { - for (int i = this.propertyNames.length; i-- > 0; ) { - ((Model) this.subject).addPropertyChangeListener(this.propertyNames[i], this.propertyChangeListener); + protected void engageSubject_() { + for (String propertyName : this.propertyNames) { + ((Model) this.subject).addPropertyChangeListener(propertyName, this.propertyChangeListener); } } @@ -205,9 +206,9 @@ public abstract class PropertyAspectAdapter } @Override - protected void disengageNonNullSubject() { - for (int i = this.propertyNames.length; i-- > 0; ) { - ((Model) this.subject).removePropertyChangeListener(this.propertyNames[i], this.propertyChangeListener); + protected void disengageSubject_() { + for (String propertyName : this.propertyNames) { + ((Model) this.subject).removePropertyChangeListener(propertyName, this.propertyChangeListener); } } @@ -231,7 +232,7 @@ public abstract class PropertyAspectAdapter * Return the aspect's value. * At this point the subject may be null. */ - protected Object buildValue() { + protected T buildValue() { return (this.subject == null) ? null : this.buildValue_(); } @@ -240,12 +241,12 @@ public abstract class PropertyAspectAdapter * At this point we can be sure that the subject is not null. * @see #buildValue() */ - protected Object buildValue_() { + protected T buildValue_() { throw new UnsupportedOperationException(); } protected void propertyChanged() { - Object old = this.value; + T old = this.value; this.value = this.buildValue(); this.fireAspectChange(old, this.value); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyCollectionValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyCollectionValueModelAdapter.java index 8414392fbf..5e37718f14 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyCollectionValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyCollectionValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,7 +9,6 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; -import java.util.Collection; import java.util.Iterator; import org.eclipse.jpt.utility.internal.iterators.EmptyIterator; @@ -28,18 +27,18 @@ import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; * If the property's value is null, an empty iterator is returned * (i.e. you can't have a collection with a null element). */ -public class PropertyCollectionValueModelAdapter +public class PropertyCollectionValueModelAdapter<E> extends AbstractModel - implements CollectionValueModel + implements CollectionValueModel<E> { /** The wrapped property value model. */ - protected final PropertyValueModel valueHolder; + protected final PropertyValueModel<? extends E> valueHolder; /** A listener that forwards any events fired by the value holder. */ protected final PropertyChangeListener propertyChangeListener; /** Cache the value. */ - protected Object value; + protected E value; // ********** constructors/initialization ********** @@ -47,7 +46,7 @@ public class PropertyCollectionValueModelAdapter /** * Wrap the specified ListValueModel. */ - public PropertyCollectionValueModelAdapter(PropertyValueModel valueHolder) { + public PropertyCollectionValueModelAdapter(PropertyValueModel<? extends E> valueHolder) { super(); if (valueHolder == null) { throw new NullPointerException(); @@ -69,8 +68,9 @@ public class PropertyCollectionValueModelAdapter */ protected PropertyChangeListener buildPropertyChangeListener() { return new PropertyChangeListener() { + @SuppressWarnings("unchecked") public void propertyChanged(PropertyChangeEvent e) { - PropertyCollectionValueModelAdapter.this.valueChanged(e.newValue()); + PropertyCollectionValueModelAdapter.this.valueChanged((E) e.newValue()); } @Override public String toString() { @@ -82,11 +82,11 @@ public class PropertyCollectionValueModelAdapter // ********** CollectionValueModel implementation ********** - public Iterator iterator() { + public Iterator<E> iterator() { return (this.value == null) ? - EmptyIterator.instance() + EmptyIterator.<E>instance() : - new SingleElementIterator(this.value); + new SingleElementIterator<E>(this.value); } public int size() { @@ -155,14 +155,14 @@ public class PropertyCollectionValueModelAdapter // ********** behavior ********** protected void engageModel() { - this.valueHolder.addPropertyChangeListener(ValueModel.VALUE, this.propertyChangeListener); + this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.propertyChangeListener); // synch our value *after* we start listening to the value holder, // since its value might change when a listener is added this.value = this.valueHolder.value(); } protected void disengageModel() { - this.valueHolder.removePropertyChangeListener(ValueModel.VALUE, this.propertyChangeListener); + this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.propertyChangeListener); // clear out the value when we are not listening to the value holder this.value = null; } @@ -171,10 +171,10 @@ public class PropertyCollectionValueModelAdapter * synchronize our internal value with the wrapped value * and fire the appropriate events */ - protected void valueChanged(Object newValue) { + protected void valueChanged(E newValue) { // put in "empty" check so we don't fire events unnecessarily if (this.value != null) { - Object oldValue = this.value; + E oldValue = this.value; this.value = null; this.fireItemRemoved(VALUES, oldValue); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModel.java index 0625fba89e..31481f2380 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModel.java @@ -9,17 +9,20 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; +import org.eclipse.jpt.utility.internal.model.Model; + /** - * Extend ValueModel to allow the setting of the property's value. + * Interface used to abstract property accessing and + * change notification and make it more pluggable. */ -public interface PropertyValueModel - extends ValueModel +public interface PropertyValueModel<T> + extends Model { /** - * Set the value and fire a property change notification. - * @see ValueModel#VALUE + * Return the property's value. */ - void setValue(Object value); + T value(); + String VALUE = "value"; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModelWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModelWrapper.java index eb0d4f1895..b94d9bc798 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModelWrapper.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModelWrapper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -20,25 +20,24 @@ import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; * another property value model, "lazily" listen to it, and propagate * its change notifications. */ -public abstract class PropertyValueModelWrapper +public abstract class PropertyValueModelWrapper<T> extends AbstractModel - implements PropertyValueModel { /** The wrapped property value model. */ - protected final PropertyValueModel valueHolder; + protected final PropertyValueModel<? extends T> valueHolder; /** A listener that allows us to synch with changes to the wrapped value holder. */ protected final PropertyChangeListener valueChangeListener; - // ********** constructors ********** + // ********** constructors/initialization ********** /** * Construct a property value model with the specified wrapped * property value model. The value holder is required. */ - protected PropertyValueModelWrapper(PropertyValueModel valueHolder) { + protected PropertyValueModelWrapper(PropertyValueModel<? extends T> valueHolder) { super(); if (valueHolder == null) { throw new NullPointerException(); @@ -47,12 +46,9 @@ public abstract class PropertyValueModelWrapper this.valueChangeListener = this.buildValueChangeListener(); } - - // ********** initialization ********** - @Override protected ChangeSupport buildChangeSupport() { - return new SingleAspectChangeSupport(this, PropertyChangeListener.class, VALUE); + return new SingleAspectChangeSupport(this, PropertyChangeListener.class, PropertyValueModel.VALUE); } protected PropertyChangeListener buildValueChangeListener() { @@ -75,7 +71,7 @@ public abstract class PropertyValueModelWrapper */ @Override public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { - if (this.hasNoPropertyChangeListeners(VALUE)) { + if (this.hasNoPropertyChangeListeners(PropertyValueModel.VALUE)) { this.engageValueHolder(); } super.addPropertyChangeListener(listener); @@ -86,7 +82,7 @@ public abstract class PropertyValueModelWrapper */ @Override public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { - if (propertyName == VALUE && this.hasNoPropertyChangeListeners(VALUE)) { + if (propertyName == PropertyValueModel.VALUE && this.hasNoPropertyChangeListeners(PropertyValueModel.VALUE)) { this.engageValueHolder(); } super.addPropertyChangeListener(propertyName, listener); @@ -98,7 +94,7 @@ public abstract class PropertyValueModelWrapper @Override public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { super.removePropertyChangeListener(listener); - if (this.hasNoPropertyChangeListeners(VALUE)) { + if (this.hasNoPropertyChangeListeners(PropertyValueModel.VALUE)) { this.disengageValueHolder(); } } @@ -109,7 +105,7 @@ public abstract class PropertyValueModelWrapper @Override public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { super.removePropertyChangeListener(propertyName, listener); - if (propertyName == VALUE && this.hasNoPropertyChangeListeners(VALUE)) { + if (propertyName == PropertyValueModel.VALUE && this.hasNoPropertyChangeListeners(PropertyValueModel.VALUE)) { this.disengageValueHolder(); } } @@ -121,14 +117,14 @@ public abstract class PropertyValueModelWrapper * Begin listening to the value holder. */ protected void engageValueHolder() { - this.valueHolder.addPropertyChangeListener(VALUE, this.valueChangeListener); + this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener); } /** * Stop listening to the value holder. */ protected void disengageValueHolder() { - this.valueHolder.removePropertyChangeListener(VALUE, this.valueChangeListener); + this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener); } @Override diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleCollectionValueModel.java index 3dc3dfd460..5e94b40327 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleCollectionValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleCollectionValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -26,7 +26,7 @@ import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; */ public class SimpleCollectionValueModel<E> extends AbstractModel - implements CollectionValueModel, Collection<E> + implements CollectionValueModel<E>, Collection<E> { /** The collection. */ protected Collection<E> collection; diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleListValueModel.java index 6102f68698..b5dc9d7554 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleListValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleListValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -27,7 +27,7 @@ import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; */ public class SimpleListValueModel<E> extends AbstractModel - implements ListValueModel, List<E> + implements ListValueModel<E>, List<E> { /** The list. */ protected List<E> list; diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimplePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimplePropertyValueModel.java index 13f5dd366d..8967a31df6 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimplePropertyValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimplePropertyValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -15,21 +15,21 @@ import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport; import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; /** - * Implementation of PropertyValueModel that simply holds on to an + * Implementation of WritablePropertyValueModel that simply holds on to an * object and uses it as the value. */ -public class SimplePropertyValueModel +public class SimplePropertyValueModel<T> extends AbstractModel - implements PropertyValueModel + implements WritablePropertyValueModel<T> { /** The value. */ - protected Object value; + protected T value; /** * Construct a PropertyValueModel for the specified value. */ - public SimplePropertyValueModel(Object value) { + public SimplePropertyValueModel(T value) { super(); this.value = value; } @@ -47,12 +47,12 @@ public class SimplePropertyValueModel } - public Object value() { + public T value() { return this.value; } - public void setValue(Object value) { - Object old = this.value; + public void setValue(T value) { + T old = this.value; this.value = value; this.firePropertyChanged(VALUE, old, value); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SortedListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SortedListValueModelAdapter.java index 449cc1e62f..f94552adba 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SortedListValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SortedListValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -35,14 +35,14 @@ import org.eclipse.jpt.utility.internal.model.event.CollectionChangeEvent; * we do not have any listeners. This should not be too painful since, * most likely, client objects will also be listeners. */ -public class SortedListValueModelAdapter - extends CollectionListValueModelAdapter +public class SortedListValueModelAdapter<E> + extends CollectionListValueModelAdapter<E> { /** * A comparator used for sorting the elements; * if it is null, we use "natural ordering". */ - protected Comparator comparator; + protected Comparator<E> comparator; // ********** constructors ********** @@ -51,7 +51,7 @@ public class SortedListValueModelAdapter * Wrap the specified collection value model and sort its contents * using the specified comparator. */ - public SortedListValueModelAdapter(CollectionValueModel collectionHolder, Comparator comparator) { + public SortedListValueModelAdapter(CollectionValueModel<? extends E> collectionHolder, Comparator<E> comparator) { super(collectionHolder); this.comparator = comparator; } @@ -60,7 +60,7 @@ public class SortedListValueModelAdapter * Wrap the specified collection value model and sort its contents * based on the elements' "natural ordering". */ - public SortedListValueModelAdapter(CollectionValueModel collectionHolder) { + public SortedListValueModelAdapter(CollectionValueModel<? extends E> collectionHolder) { this(collectionHolder, null); } @@ -68,22 +68,22 @@ public class SortedListValueModelAdapter * Wrap the specified list value model and sort its contents * using the specified comparator. */ - public SortedListValueModelAdapter(ListValueModel listHolder, Comparator comparator) { - this(new ListCollectionValueModelAdapter(listHolder), comparator); + public SortedListValueModelAdapter(ListValueModel<? extends E> listHolder, Comparator<E> comparator) { + this(new ListCollectionValueModelAdapter<E>(listHolder), comparator); } /** * Wrap the specified list value model and sort its contents * based on the elements' "natural ordering". */ - public SortedListValueModelAdapter(ListValueModel listHolder) { + public SortedListValueModelAdapter(ListValueModel<? extends E> listHolder) { this(listHolder, null); } // ********** accessors ********** - public void setComparator(Comparator comparator) { + public void setComparator(Comparator<E> comparator) { this.comparator = comparator; this.sortList(); } @@ -117,12 +117,13 @@ public class SortedListValueModelAdapter */ protected void sortList() { // save the unsorted state of the sorted list so we can minimize the number of "replaced" items - ArrayList unsortedList = (ArrayList) this.list.clone(); + @SuppressWarnings("unchecked") + ArrayList<E> unsortedList = (ArrayList<E>) this.list.clone(); Collections.sort(this.list, this.comparator); Range diffRange = CollectionTools.identityDiffRange(unsortedList, this.list); if (diffRange.size > 0) { - List unsortedItems = unsortedList.subList(diffRange.start, diffRange.end + 1); - List sortedItems = this.list.subList(diffRange.start, diffRange.end + 1); + List<E> unsortedItems = unsortedList.subList(diffRange.start, diffRange.end + 1); + List<E> sortedItems = this.list.subList(diffRange.start, diffRange.end + 1); this.fireItemsReplaced(LIST_VALUES, diffRange.start, sortedItems, unsortedItems); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StatePropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StatePropertyValueModelAdapter.java new file mode 100644 index 0000000000..cdbabb5711 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StatePropertyValueModelAdapter.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.model.Model; +import org.eclipse.jpt.utility.internal.model.event.StateChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.StateChangeListener; + +/** + * This abstract class provides the infrastructure needed to wrap + * a model, "lazily" listen to it, and convert + * its state change notifications into property value model change + * notifications. + * + * Subclasses must override: + * - #buildValue() + * to return the current property value, as derived from the + * current model + * + * Subclasses might want to override: + * - #stateChanged(StateChangeEvent e) + * to improve performance (by not recalculating the value, if possible) + */ +public abstract class StatePropertyValueModelAdapter<T> + extends AspectPropertyValueModelAdapter<T> +{ + /** The wrapped model. */ + protected final Model model; + + /** A listener that allows us to synch with changes to the wrapped model. */ + protected final StateChangeListener stateChangeListener; + + + // ********** constructor/initialization ********** + + /** + * Construct a property value model with the specified wrapped model. + */ + protected StatePropertyValueModelAdapter(Model model) { + super(); + this.model = model; + this.stateChangeListener = this.buildStateChangeListener(); + } + + protected StateChangeListener buildStateChangeListener() { + return new StateChangeListener() { + public void stateChanged(StateChangeEvent event) { + StatePropertyValueModelAdapter.this.stateChanged(event); + } + @Override + public String toString() { + return "state change listener"; + } + }; + } + + + // ********** behavior ********** + + /** + * Start listening to the model. + */ + @Override + protected void engageModel_() { + this.model.addStateChangeListener(this.stateChangeListener); + } + + /** + * Stop listening to the model. + */ + @Override + protected void disengageModel_() { + this.model.removeStateChangeListener(this.stateChangeListener); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.model); + } + + + // ********** state change support ********** + + /** + * The model's state changed; + * propagate the change notification appropriately. + */ + protected void stateChanged(StateChangeEvent e) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticCollectionValueModel.java new file mode 100644 index 0000000000..005dc3db67 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticCollectionValueModel.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Collection; +import java.util.Iterator; + +import org.eclipse.jpt.utility.internal.StringTools; +import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator; +import org.eclipse.jpt.utility.internal.model.AbstractModel; + +/** + * Implementation of CollectionValueModel that can be used for + * returning an iterator on a static collection, but still allows listeners to be added. + * Listeners will NEVER be notified of any changes, because there should be none. + */ +public class StaticCollectionValueModel<E> + extends AbstractModel + implements CollectionValueModel<E> +{ + /** The collection. */ + protected final Collection<? extends E> collection; + + private static final long serialVersionUID = 1L; + + + /** + * Construct a static CollectionValueModel for the specified collection. + */ + public StaticCollectionValueModel(Collection<? extends E> collection) { + super(); + if (collection == null) { + throw new NullPointerException(); + } + this.collection = collection; + } + + // ********** CollectionValueModel implementation ********** + + public int size() { + return this.collection.size(); + } + + public Iterator<E> iterator() { + return new ReadOnlyIterator<E>(this.collection.iterator()); + } + + + // ********** Object overrides ********** + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.collection); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticListValueModel.java new file mode 100644 index 0000000000..bd8987c747 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticListValueModel.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.eclipse.jpt.utility.internal.StringTools; +import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator; +import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator; +import org.eclipse.jpt.utility.internal.model.AbstractModel; + +/** + * Implementation of ListValueModel that can be used for + * returning a list iterator on a static list, but still allows listeners to be added. + * Listeners will NEVER be notified of any changes, because there should be none. + */ +public class StaticListValueModel<E> + extends AbstractModel + implements ListValueModel<E> +{ + /** The value. */ + protected final List<? extends E> list; + + private static final long serialVersionUID = 1L; + + + /** + * Construct a static ListValueModel for the specified list. + */ + public StaticListValueModel(List<? extends E> list) { + super(); + if (list == null) { + throw new NullPointerException(); + } + this.list = list; + } + + + // ********** ListValueModel implementation ********** + + public Iterator<E> iterator() { + return new ReadOnlyIterator<E>(this.list.iterator()); + } + + public ListIterator<E> listIterator() { + return new ReadOnlyListIterator<E>(this.list.listIterator()); + } + + public int size() { + return this.list.size(); + } + + public E get(int index) { + return this.list.get(index); + } + + public Object[] toArray() { + return this.list.toArray(); + } + + + // ********** Object overrides ********** + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.list); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticPropertyValueModel.java new file mode 100644 index 0000000000..0a6c1d41e0 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticPropertyValueModel.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.StringTools; +import org.eclipse.jpt.utility.internal.model.AbstractModel; + +/** + * Implementation of PropertyValueModel that can be used for + * returning a static value, but still allows listeners to be added. + * Listeners will NEVER be notified of any changes, because there should be none. + */ +public class StaticPropertyValueModel<T> + extends AbstractModel + implements PropertyValueModel<T> +{ + /** The value. */ + protected final T value; + + private static final long serialVersionUID = 1L; + + + /** + * Construct a static PropertyValueModel for the specified value. + */ + public StaticPropertyValueModel(T value) { + super(); + this.value = value; + } + + + // ********** PropertyValueModel implementation ********** + + public T value() { + return this.value; + } + + + // ********** Object overrides ********** + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.value); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticTreeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticTreeValueModel.java new file mode 100644 index 0000000000..9f4780a442 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticTreeValueModel.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Iterator; + +import org.eclipse.jpt.utility.internal.CollectionTools; +import org.eclipse.jpt.utility.internal.StringTools; +import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator; +import org.eclipse.jpt.utility.internal.model.AbstractModel; + +/** + * Implementation of TreeValueModel that can be used for + * returning an iterator on a static tree, but still allows listeners to be added. + * Listeners will NEVER be notified of any changes, because there should be none. + */ +public class StaticTreeValueModel<E> + extends AbstractModel + implements TreeValueModel<E> +{ + /** The tree's nodes. */ + protected final Iterable<? extends E> nodes; + + private static final long serialVersionUID = 1L; + + + /** + * Construct a read-only TreeValueModel for the specified nodes. + */ + public StaticTreeValueModel(Iterable<? extends E> nodes) { + super(); + if (nodes == null) { + throw new NullPointerException(); + } + this.nodes = nodes; + } + + // ********** TreeValueModel implementation ********** + + public Iterator<E> nodes() { + return new ReadOnlyIterator<E>(this.nodes.iterator()); + } + + + // ********** Object overrides ********** + + @Override + public String toString() { + return StringTools.buildToStringFor(this, CollectionTools.collection(this.nodes())); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationListValueModelAdapter.java index 60f464fd4f..582b1a362b 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationListValueModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationListValueModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -10,6 +10,7 @@ package org.eclipse.jpt.utility.internal.model.value; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -35,15 +36,16 @@ import org.eclipse.jpt.utility.internal.model.event.ListChangeEvent; * we do not have any listeners. This should not be too painful since, * most likely, client objects will also be listeners. */ -public class TransformationListValueModelAdapter - extends ListValueModelWrapper +public class TransformationListValueModelAdapter<E1, E2> + extends ListValueModelWrapper<E1> + implements ListValueModel<E2> { /** This transforms the items, unless the subclass overrides #transformItem(Object). */ - protected Transformer transformer; + protected Transformer<E1, E2> transformer; /** The list of transformed items. */ - protected final List transformedList; + protected final List<E2> transformedList; // ********** constructors ********** @@ -51,52 +53,52 @@ public class TransformationListValueModelAdapter /** * Constructor - the list holder is required. */ - public TransformationListValueModelAdapter(ListValueModel listHolder, Transformer transformer) { + public TransformationListValueModelAdapter(ListValueModel<? extends E1> listHolder, Transformer<E1, E2> transformer) { super(listHolder); this.transformer = transformer; - this.transformedList = new ArrayList(); + this.transformedList = new ArrayList<E2>(); } /** * Constructor - the list holder is required. */ - public TransformationListValueModelAdapter(ListValueModel listHolder) { - this(listHolder, Transformer.Null.instance()); + public TransformationListValueModelAdapter(ListValueModel<? extends E1> listHolder) { + this(listHolder, Transformer.Null.<E1, E2>instance()); } /** * Constructor - the collection holder is required. */ - public TransformationListValueModelAdapter(CollectionValueModel collectionHolder, Transformer transformer) { - this(new CollectionListValueModelAdapter(collectionHolder), transformer); + public TransformationListValueModelAdapter(CollectionValueModel<? extends E1> collectionHolder, Transformer<E1, E2> transformer) { + this(new CollectionListValueModelAdapter<E1>(collectionHolder), transformer); } /** * Constructor - the collection holder is required. */ - public TransformationListValueModelAdapter(CollectionValueModel collectionHolder) { - this(new CollectionListValueModelAdapter(collectionHolder)); + public TransformationListValueModelAdapter(CollectionValueModel<? extends E1> collectionHolder) { + this(new CollectionListValueModelAdapter<E1>(collectionHolder)); } // ********** ListValueModel implementation ********** - public ListIterator listIterator() { - // try to prevent backdoor modification of the list - return new ReadOnlyListIterator(this.transformedList); + public Iterator<E2> iterator() { + return this.listIterator(); } - @Override - public Object get(int index) { + public ListIterator<E2> listIterator() { + return new ReadOnlyListIterator<E2>(this.transformedList); + } + + public E2 get(int index) { return this.transformedList.get(index); } - @Override public int size() { return this.transformedList.size(); } - @Override public Object[] toArray() { return this.transformedList.toArray(); } @@ -121,29 +123,29 @@ public class TransformationListValueModelAdapter /** * Transform the items associated with the specified event. */ - protected List transformItems(ListChangeEvent e) { - return this.transformItems(e.items(), e.itemsSize()); + protected List<E2> transformItems(ListChangeEvent e) { + return this.transformItems(this.items(e), e.itemsSize()); } /** * Transform the items in the specified list value model. */ - protected List transformItems(ListValueModel lvm) { + protected List<E2> transformItems(ListValueModel<? extends E1> lvm) { return this.transformItems(lvm.listIterator(), lvm.size()); } /** * Transform the replaced items associated with the specified event. */ - protected List transformReplacedItems(ListChangeEvent e) { - return this.transformItems(e.replacedItems(), e.itemsSize()); + protected List<E2> transformReplacedItems(ListChangeEvent e) { + return this.transformItems(this.replacedItems(e), e.itemsSize()); } /** * Transform the specified items. */ - protected List transformItems(ListIterator items, int size) { - List result = new ArrayList(size); + protected List<E2> transformItems(ListIterator<? extends E1> items, int size) { + List<E2> result = new ArrayList<E2>(size); while (items.hasNext()) { result.add(this.transformItem(items.next())); } @@ -153,14 +155,14 @@ public class TransformationListValueModelAdapter /** * Transform the specified item. */ - protected Object transformItem(Object item) { + protected E2 transformItem(E1 item) { return this.transformer.transform(item); } /** * Change the transformer and rebuild the collection. */ - public void setTransformer(Transformer transformer) { + public void setTransformer(Transformer<E1, E2> transformer) { this.transformer = transformer; this.rebuildTransformedList(); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationPropertyValueModel.java index a94059940b..b89e6ec117 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationPropertyValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationPropertyValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,74 +9,72 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; -import org.eclipse.jpt.utility.internal.BidiTransformer; +import org.eclipse.jpt.utility.internal.Transformer; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; /** * A <code>TransformationPropertyValueModel</code> wraps another - * <code>PropertyValueModel</code> and uses a <code>BidiTransformer</code> - * to:<ul> - * <li>transform the wrapped value before it is returned by <code>value()</code> - * <li>"reverse-transform" the new value that comes in via - * <code>setValue(Object)</code> - * </ul> - * As an alternative to building a <code>BidiTransformer</code>, + * <code>PropertyValueModel</code> and uses a <code>Transformer</code> + * to transform the wrapped value before it is returned by <code>value()</code>. + * <p> + * As an alternative to building a <code>Transformer</code>, * a subclass of <code>TransformationPropertyValueModel</code> can - * override the <code>transform(Object)</code> and - * <code>reverseTransform(Object)</code> methods. + * either override the <code>transform_(Object)</code> method or, + * if something other than null should be returned when the wrapped value + * is null, override the <code>transform(Object)</code> method. */ -public class TransformationPropertyValueModel - extends PropertyValueModelWrapper +public class TransformationPropertyValueModel<T1, T2> + extends PropertyValueModelWrapper<T1> + implements PropertyValueModel<T2> { - private final BidiTransformer transformer; + protected final Transformer<T1, T2> transformer; - // ********** constructors ********** + // ********** constructors/initialization ********** /** * Construct a property value model with the specified nested - * property value model and a disabled transformer. + * property value model and the default transformer. * Use this constructor if you want to override the - * <code>transform(Object)</code> and <code>reverseTransform(Object)</code> - * methods instead of building a <code>BidiTransformer</code>. + * <code>transform_(Object)</code> or <code>transform(Object)</code> + * method instead of building a <code>Transformer</code>. */ - public TransformationPropertyValueModel(PropertyValueModel valueHolder) { - this(valueHolder, BidiTransformer.Disabled.instance()); + public TransformationPropertyValueModel(PropertyValueModel<? extends T1> valueHolder) { + super(valueHolder); + this.transformer = this.buildTransformer(); } /** * Construct an property value model with the specified nested * property value model and transformer. */ - public TransformationPropertyValueModel(PropertyValueModel valueHolder, BidiTransformer transformer) { + public TransformationPropertyValueModel(PropertyValueModel<? extends T1> valueHolder, Transformer<T1, T2> transformer) { super(valueHolder); this.transformer = transformer; } - - // ********** ValueModel implementation ********** - - public Object value() { - // transform the object returned by the nested value model before returning it - return this.transform(this.valueHolder.value()); + protected Transformer<T1, T2> buildTransformer() { + return new DefaultTransformer(); } // ********** PropertyValueModel implementation ********** - public void setValue(Object value) { - // "reverse-transform" the object before passing it to the the nested value model - this.valueHolder.setValue(this.reverseTransform(value)); + public T2 value() { + // transform the object returned by the nested value model before returning it + return this.transform(this.valueHolder.value()); } // ********** PropertyValueModelWrapper implementation ********** - @Override + @Override protected void valueChanged(PropertyChangeEvent e) { // transform the values before propagating the change event - Object oldValue = this.transform(e.oldValue()); - Object newValue = this.transform(e.newValue()); + @SuppressWarnings("unchecked") + Object oldValue = this.transform((T1) e.oldValue()); + @SuppressWarnings("unchecked") + Object newValue = this.transform((T1) e.newValue()); this.firePropertyChanged(VALUE, oldValue, newValue); } @@ -84,19 +82,32 @@ public class TransformationPropertyValueModel // ********** behavior ********** /** - * Transform the specified object and return the result. - * This is called by #value(). + * Transform the specified value and return the result. + * This is called by #value() and #valueChanged(PropertyChangeEvent). */ - protected Object transform(Object value) { + protected T2 transform(T1 value) { return this.transformer.transform(value); } /** - * "Reverse-transform" the specified object and return the result. - * This is called by #setValue(Object). + * Transform the specified, non-null, value and return the result. + */ + protected T2 transform_(T1 value) { + throw new UnsupportedOperationException(); + } + + + // ********** default transformer ********** + + /** + * The default transformer will return null if the wrapped value is null. + * If the wrapped value is not null, it is transformed by a subclass + * implementation of #transform_(Object). */ - protected Object reverseTransform(Object value) { - return this.transformer.reverseTransform(value); + protected class DefaultTransformer implements Transformer<T1, T2> { + public T2 transform(T1 value) { + return (value == null) ? null : TransformationPropertyValueModel.this.transform_(value); + } } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationWritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationWritablePropertyValueModel.java new file mode 100644 index 0000000000..a3ce7d5fef --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationWritablePropertyValueModel.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.BidiTransformer; + +/** + * A <code>TransformationWritablePropertyValueModel</code> wraps another + * <code>WritablePropertyValueModel</code> and uses a <code>BidiTransformer</code> + * to:<ul> + * <li>transform the wrapped value before it is returned by <code>value()</code> + * <li>"reverse-transform" the new value that comes in via + * <code>setValue(Object)</code> + * </ul> + * As an alternative to building a <code>BidiTransformer</code>, + * a subclass of <code>TransformationWritablePropertyValueModel</code> can + * override the <code>transform_(Object)</code> and + * <code>reverseTransform_(Object)</code> methods; or, + * if something other than null should be returned when the wrapped value + * is null or the new value is null, override the <code>transform(Object)</code> + * and <code>reverseTransform(Object)</code> methods. + */ +public class TransformationWritablePropertyValueModel<T1, T2> + extends TransformationPropertyValueModel<T1, T2> + implements WritablePropertyValueModel<T2> +{ + + // ********** constructors/initialization ********** + + /** + * Construct a writable property value model with the specified nested + * writable property value model and the default bidi transformer. + * Use this constructor if you want to override the + * <code>transform_(Object)</code> and <code>reverseTransform_(Object)</code> + * (or <code>transform(Object)</code> and <code>reverseTransform(Object)</code>) + * methods instead of building a <code>BidiTransformer</code>. + */ + public TransformationWritablePropertyValueModel(WritablePropertyValueModel<T1> valueHolder) { + super(valueHolder); + } + + /** + * Construct a writable property value model with the specified nested + * writable property value model and bidi transformer. + */ + public TransformationWritablePropertyValueModel(WritablePropertyValueModel<T1> valueHolder, BidiTransformer<T1, T2> transformer) { + super(valueHolder, transformer); + } + + @Override + protected BidiTransformer<T1, T2> buildTransformer() { + return new DefaultBidiTransformer(); + } + + + // ********** WritablePropertyValueModel implementation ********** + + public void setValue(T2 value) { + // "reverse-transform" the object before passing it to the the nested value model + this.valueHolder().setValue(this.reverseTransform(value)); + } + + + // ********** behavior ********** + + /** + * "Reverse-transform" the specified value and return the result. + * This is called by #setValue(Object). + */ + protected T1 reverseTransform(T2 value) { + return this.transformer().reverseTransform(value); + } + + /** + * "Reverse-transform" the specified, non-null, value and return the result. + */ + protected T1 reverseTransform_(T2 value) { + throw new UnsupportedOperationException(); + } + + + // ********** queries ********** + + /** + * Our constructors accept only a WritablePropertyValueModel<T1>. + */ + @SuppressWarnings("unchecked") + protected WritablePropertyValueModel<T1> valueHolder() { + return (WritablePropertyValueModel<T1>) this.valueHolder; + } + + /** + * Our constructors accept only a bidirectional transformer. + */ + protected BidiTransformer<T1, T2> transformer() { + return (BidiTransformer<T1, T2>) this.transformer; + } + + + // ********** default bidi transformer ********** + + /** + * The default bidi transformer will return null if the wrapped value is null. + * If the wrapped value is not null, it is transformed by a subclass + * implementation of #transform_(Object). + * The default bidi transformer will also return null if the new value is null. + * If the new value is not null, it is reverse-transformed by a subclass + * implementation of #reverseTransform_(Object). + */ + protected class DefaultBidiTransformer + extends DefaultTransformer + implements BidiTransformer<T1, T2> + { + public T1 reverseTransform(T2 value) { + return (value == null) ? null : TransformationWritablePropertyValueModel.this.reverseTransform_(value); + } + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeAspectAdapter.java index 549cd66c23..66a6bb4fe6 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeAspectAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeAspectAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,6 +9,8 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value; +import java.util.Arrays; +import java.util.Collection; import java.util.Iterator; import org.eclipse.jpt.utility.internal.iterators.EmptyIterator; @@ -19,6 +21,8 @@ import org.eclipse.jpt.utility.internal.model.listener.TreeChangeListener; /** * This extension of PropertyAdapter provides TreeChange support. + * This allows us to convert a set of one or more trees into + * a single tree, NODES. * * The typical subclass will override the following methods: * #nodes_() @@ -29,14 +33,15 @@ import org.eclipse.jpt.utility.internal.model.listener.TreeChangeListener; * override this method only if returning an empty iterator when the * subject is null is unacceptable */ -public abstract class TreeAspectAdapter - extends AspectAdapter - implements TreeValueModel +public abstract class TreeAspectAdapter<S extends Model, E> + extends AspectAdapter<S> + implements TreeValueModel<E> { /** - * The name of the subject's tree that we use for the value. + * The name of the subject's trees that we use for the value. */ - protected final String treeName; + protected final String[] treeNames; + protected static final String[] EMPTY_TREE_NAMES = new String[0]; /** A listener that listens to the subject's tree aspect. */ protected final TreeChangeListener treeChangeListener; @@ -48,20 +53,46 @@ public abstract class TreeAspectAdapter * Construct a TreeAspectAdapter for the specified subject * and tree. */ - protected TreeAspectAdapter(String treeName, Model subject) { - this(new ReadOnlyPropertyValueModel(subject), treeName); + protected TreeAspectAdapter(String treeName, S subject) { + this(new String[] {treeName}, subject); + } + + /** + * Construct a TreeAspectAdapter for the specified subject + * and trees. + */ + protected TreeAspectAdapter(String[] treeNames, S subject) { + this(new StaticPropertyValueModel<S>(subject), treeNames); } /** * Construct a TreeAspectAdapter for the specified subject holder - * and tree. + * and trees. */ - protected TreeAspectAdapter(ValueModel subjectHolder, String treeName) { + protected TreeAspectAdapter(PropertyValueModel<? extends S> subjectHolder, String... treeNames) { super(subjectHolder); - this.treeName = treeName; + this.treeNames = treeNames; this.treeChangeListener = this.buildTreeChangeListener(); } + /** + * Construct a TreeAspectAdapter for the specified subject holder + * and trees. + */ + protected TreeAspectAdapter(PropertyValueModel<? extends S> subjectHolder, Collection<String> treeNames) { + this(subjectHolder, treeNames.toArray(new String[treeNames.size()])); + } + + /** + * Construct a TreeAspectAdapter for an "unchanging" tree in + * the specified subject. This is useful for a tree aspect that does not + * change for a particular subject; but the subject will change, resulting in + * a new tree. + */ + protected TreeAspectAdapter(PropertyValueModel<? extends S> subjectHolder) { + this(subjectHolder, EMPTY_TREE_NAMES); + } + // ********** initialization ********** @@ -85,7 +116,7 @@ public abstract class TreeAspectAdapter } @Override public String toString() { - return "tree change listener: " + TreeAspectAdapter.this.treeName; + return "tree change listener: " + Arrays.asList(TreeAspectAdapter.this.treeNames); } }; } @@ -96,8 +127,8 @@ public abstract class TreeAspectAdapter /** * Return the nodes of the subject's tree aspect. */ - public Iterator nodes() { - return (this.subject == null) ? EmptyIterator.instance() : this.nodes_(); + public Iterator<E> nodes() { + return (this.subject == null) ? EmptyIterator.<E>instance() : this.nodes_(); } /** @@ -105,7 +136,7 @@ public abstract class TreeAspectAdapter * At this point we can be sure that the subject is not null. * @see #nodes() */ - protected Iterator nodes_() { + protected Iterator<E> nodes_() { throw new UnsupportedOperationException(); } @@ -138,18 +169,27 @@ public abstract class TreeAspectAdapter } @Override - protected void engageNonNullSubject() { - ((Model) this.subject).addTreeChangeListener(this.treeName, this.treeChangeListener); + protected void engageSubject_() { + for (String treeName : this.treeNames) { + ((Model) this.subject).addTreeChangeListener(treeName, this.treeChangeListener); + } } @Override - protected void disengageNonNullSubject() { - ((Model) this.subject).removeTreeChangeListener(this.treeName, this.treeChangeListener); + protected void disengageSubject_() { + for (String treeName : this.treeNames) { + ((Model) this.subject).removeTreeChangeListener(treeName, this.treeChangeListener); + } } @Override public void toString(StringBuilder sb) { - sb.append(this.treeName); + for (int i = 0; i < this.treeNames.length; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(this.treeNames[i]); + } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeNodeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeNodeValueModel.java index 418e73769d..81eadb03b2 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeNodeValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeNodeValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -10,7 +10,7 @@ package org.eclipse.jpt.utility.internal.model.value; /** - * Extend PropertyValueModel to better support the TreeModelAdapter class. + * Extend WritablePropertyValueModel to better support TreeModelAdapter. * * Implementors of this interface should fire a "state change" event * whenever the node's internal state changes in a way that the @@ -22,30 +22,30 @@ package org.eclipse.jpt.utility.internal.model.value; * * @see AbstractTreeNodeValueModel */ -public interface TreeNodeValueModel - extends PropertyValueModel +public interface TreeNodeValueModel<T> + extends WritablePropertyValueModel<T> { /** * Return the node's parent node; null if the node * is the root. */ - TreeNodeValueModel parent(); + TreeNodeValueModel<T> parent(); /** * Return the path to the node. */ - TreeNodeValueModel[] path(); + TreeNodeValueModel<T>[] path(); /** * Return a list value model of the node's child nodes. */ - ListValueModel childrenModel(); + ListValueModel<TreeNodeValueModel<T>> childrenModel(); /** * Return the node's child at the specified index. */ - TreeNodeValueModel child(int index); + TreeNodeValueModel<T> child(int index); /** * Return the size of the node's list of children. @@ -55,7 +55,7 @@ public interface TreeNodeValueModel /** * Return the index in the node's list of children of the specified child. */ - int indexOfChild(TreeNodeValueModel child); + int indexOfChild(TreeNodeValueModel<T> child); /** * Return whether the node is a leaf (i.e. it has no children) diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreePropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreePropertyValueModelAdapter.java new file mode 100644 index 0000000000..d0bcd1bbaf --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreePropertyValueModelAdapter.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.model.event.TreeChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.TreeChangeListener; + +/** + * This abstract class provides the infrastructure needed to wrap + * a tree value model, "lazily" listen to it, and convert + * its change notifications into property value model change + * notifications. + * + * Subclasses must override: + * - #buildValue() + * to return the current property value, as derived from the + * current collection value + * + * Subclasses might want to override: + * - #stateChanged(StateChangeEvent e) + * to improve performance (by not recalculating the value, if possible) + */ +public abstract class TreePropertyValueModelAdapter<T> + extends AspectPropertyValueModelAdapter<T> +{ + /** The wrapped tree value model. */ + protected final TreeValueModel<?> treeHolder; + + /** A listener that allows us to synch with changes to the wrapped tree holder. */ + protected final TreeChangeListener treeChangeListener; + + + // ********** constructor/initialization ********** + + /** + * Construct a property value model with the specified wrapped + * tree value model. + */ + protected TreePropertyValueModelAdapter(TreeValueModel<?> treeHolder) { + super(); + this.treeHolder = treeHolder; + this.treeChangeListener = this.buildTreeChangeListener(); + } + + protected TreeChangeListener buildTreeChangeListener() { + return new TreeChangeListener() { + public void nodeAdded(TreeChangeEvent event) { + TreePropertyValueModelAdapter.this.nodeAdded(event); + } + public void nodeRemoved(TreeChangeEvent event) { + TreePropertyValueModelAdapter.this.nodeRemoved(event); + } + public void treeCleared(TreeChangeEvent event) { + TreePropertyValueModelAdapter.this.treeCleared(event); + } + public void treeChanged(TreeChangeEvent event) { + TreePropertyValueModelAdapter.this.treeChanged(event); + } + @Override + public String toString() { + return "tree change listener"; + } + }; + } + + + // ********** behavior ********** + + /** + * Start listening to the tree holder. + */ + @Override + protected void engageModel_() { + this.treeHolder.addTreeChangeListener(this.treeChangeListener); + } + + /** + * Stop listening to the tree holder. + */ + @Override + protected void disengageModel_() { + this.treeHolder.removeTreeChangeListener(this.treeChangeListener); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.treeHolder); + } + + + // ********** state change support ********** + + /** + * Nodes were added to the wrapped tree holder; + * propagate the change notification appropriately. + */ + protected void nodeAdded(TreeChangeEvent event) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + + /** + * Nodes were removed from the wrapped tree holder; + * propagate the change notification appropriately. + */ + protected void nodeRemoved(TreeChangeEvent event) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + + /** + * The wrapped tree holder was cleared; + * propagate the change notification appropriately. + */ + protected void treeCleared(TreeChangeEvent event) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + + /** + * The wrapped tree holder changed; + * propagate the change notification appropriately. + */ + protected void treeChanged(TreeChangeEvent event) { + // by default, simply recalculate the value and fire an event + this.propertyChanged(); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeValueModel.java index f631a7174e..1affcd6faa 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -17,13 +17,13 @@ import org.eclipse.jpt.utility.internal.model.Model; * Interface used to abstract tree accessing and * change notification and make it more pluggable. */ -public interface TreeValueModel +public interface TreeValueModel<E> extends Model { /** * Return the tree's nodes. */ - Iterator nodes(); + Iterator<E> nodes(); String NODES = "nodes"; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueAspectAdapter.java new file mode 100644 index 0000000000..34651e2c20 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueAspectAdapter.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.model.ChangeSupport; +import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.StateChangeListener; + +/** + * Abstract model that provides behavior for wrapping a property + * value model and listening for changes to aspects of the *value* contained + * by the property value model. Changes to the actual value are also monitored. + * + * This is useful if you have a value that may change, but whose aspects can also + * change in a fashion that might be of interest to the client. + * + * NB: Clients will need to listen for two different change notifications: a property + * change event will be be fired when the value changes; a state change event + * will be fired when an aspect of the value changes. + * + * Subclasses need to override two methods: + * + * #engageValue_() + * begin listening to the appropriate aspect of the value and call + * #valueAspectChanged(Object) whenever the aspect changes + * + * #disengageValue_() + * stop listening to the appropriate aspect of the value + */ +public abstract class ValueAspectAdapter<T> + extends PropertyValueModelWrapper<T> + implements WritablePropertyValueModel<T> +{ + /** Cache the value so we can disengage. */ + protected T value; + + + // ********** constructors/initialization ********** + + /** + * Constructor - the value holder is required. + */ + protected ValueAspectAdapter(WritablePropertyValueModel<T> valueHolder) { + super(valueHolder); + } + + @Override + protected void initialize() { + super.initialize(); + this.value = null; + } + + /** + * Override to allow both property value model change and state change + * listeners. + */ + @Override + protected ChangeSupport buildChangeSupport() { + return new ChangeSupport(this); + } + + + // ********** PropertyValueModel implementation ********** + + public T value() { + return this.value; + } + + + // ********** WritablePropertyValueModel implementation ********** + + public void setValue(T value) { + this.valueHolder().setValue(value); + } + + + // ********** PropertyValueModelWrapper implementation ********** + + @Override + protected void valueChanged(PropertyChangeEvent e) { + this.disengageValue(); + this.engageValue(); + this.firePropertyChanged(e.cloneWithSource(this)); + } + + + // ********** extend change support ********** + + @Override + public synchronized void addStateChangeListener(StateChangeListener listener) { + if (this.hasNoStateChangeListeners()) { + this.engageValue(); + } + super.addStateChangeListener(listener); + } + + @Override + public synchronized void removeStateChangeListener(StateChangeListener listener) { + super.removeStateChangeListener(listener); + if (this.hasNoStateChangeListeners()) { + this.disengageValue(); + } + } + + + // ********** behavior ********** + + /** + * Start listening to the current value. + */ + protected void engageValue() { + this.value = this.valueHolder.value(); + if (this.value != null) { + this.engageValue_(); + } + } + + /** + * Start listening to the current value. + * At this point we can be sure that the value is not null. + */ + protected abstract void engageValue_(); + + /** + * Stop listening to the current value. + */ + protected void disengageValue() { + if (this.value != null) { + this.disengageValue_(); + this.value = null; + } + } + + /** + * Stop listening to the current value. + * At this point we can be sure that the value is not null. + */ + protected abstract void disengageValue_(); + + /** + * Subclasses should call this method whenever the value's aspect changes. + */ + protected void valueAspectChanged() { + this.fireStateChanged(); + } + + /** + * Our constructors accept only a WritablePropertyValueModel<T1>. + */ + @SuppressWarnings("unchecked") + protected WritablePropertyValueModel<T> valueHolder() { + return (WritablePropertyValueModel<T>) this.valueHolder; + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueCollectionAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueCollectionAdapter.java new file mode 100644 index 0000000000..f56497b23c --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueCollectionAdapter.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Arrays; + +import org.eclipse.jpt.utility.internal.model.Model; +import org.eclipse.jpt.utility.internal.model.event.CollectionChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; + +/** + * Extend ValueAspectAdapter to listen to one or more collection + * aspects of the value in the wrapped value model. + */ +public class ValueCollectionAdapter<T extends Model> + extends ValueAspectAdapter<T> +{ + + /** The names of the value's collections that we listen to. */ + protected final String[] collectionNames; + + /** Listener that listens to the value. */ + protected final CollectionChangeListener valueCollectionListener; + + + // ********** constructors ********** + + /** + * Construct an adapter for the specified value collections. + */ + public ValueCollectionAdapter(WritablePropertyValueModel<T> valueHolder, String... collectionNames) { + super(valueHolder); + this.collectionNames = collectionNames; + this.valueCollectionListener = this.buildValueCollectionListener(); + } + + + // ********** initialization ********** + + /** + * All we really care about is the fact that a Collection aspect has + * changed. Do the same thing no matter which event occurs. + */ + protected CollectionChangeListener buildValueCollectionListener() { + return new CollectionChangeListener() { + public void itemsAdded(CollectionChangeEvent e) { + ValueCollectionAdapter.this.valueAspectChanged(); + } + public void itemsRemoved(CollectionChangeEvent e) { + ValueCollectionAdapter.this.valueAspectChanged(); + } + public void collectionCleared(CollectionChangeEvent e) { + ValueCollectionAdapter.this.valueAspectChanged(); + } + public void collectionChanged(CollectionChangeEvent e) { + ValueCollectionAdapter.this.valueAspectChanged(); + } + @Override + public String toString() { + return "value collection listener: " + Arrays.asList(ValueCollectionAdapter.this.collectionNames); + } + }; + } + + @Override + protected void engageValue_() { + for (String collectionName : this.collectionNames) { + this.value.addCollectionChangeListener(collectionName, this.valueCollectionListener); + } + } + + @Override + protected void disengageValue_() { + for (String collectionName : this.collectionNames) { + this.value.removeCollectionChangeListener(collectionName, this.valueCollectionListener); + } + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueListAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueListAdapter.java new file mode 100644 index 0000000000..c6c2fceda9 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueListAdapter.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Arrays; + +import org.eclipse.jpt.utility.internal.model.Model; +import org.eclipse.jpt.utility.internal.model.event.ListChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.ListChangeListener; + +/** + * Extend ValueAspectAdapter to listen to one or more list + * aspects of the value in the wrapped value model. + */ +public class ValueListAdapter<T extends Model> + extends ValueAspectAdapter<T> +{ + + /** The names of the value's lists that we listen to. */ + protected final String[] listNames; + + /** Listener that listens to the value. */ + protected final ListChangeListener valueListListener; + + + // ********** constructors ********** + + /** + * Construct an adapter for the specified value lists. + */ + public ValueListAdapter(WritablePropertyValueModel<T> valueHolder, String... listNames) { + super(valueHolder); + this.listNames = listNames; + this.valueListListener = this.buildValueListListener(); + } + + + // ********** initialization ********** + + /** + * All we really care about is the fact that a List aspect has + * changed. Do the same thing no matter which event occurs. + */ + protected ListChangeListener buildValueListListener() { + return new ListChangeListener() { + public void itemsAdded(ListChangeEvent e) { + ValueListAdapter.this.valueAspectChanged(); + } + public void itemsRemoved(ListChangeEvent e) { + ValueListAdapter.this.valueAspectChanged(); + } + public void itemsReplaced(ListChangeEvent e) { + ValueListAdapter.this.valueAspectChanged(); + } + public void itemsMoved(ListChangeEvent e) { + ValueListAdapter.this.valueAspectChanged(); + } + public void listCleared(ListChangeEvent e) { + ValueListAdapter.this.valueAspectChanged(); + } + public void listChanged(ListChangeEvent e) { + ValueListAdapter.this.valueAspectChanged(); + } + @Override + public String toString() { + return "value list listener: " + Arrays.asList(ValueListAdapter.this.listNames); + } + }; + } + + @Override + protected void engageValue_() { + for (String listName : this.listNames) { + this.value.addListChangeListener(listName, this.valueListListener); + } + } + + @Override + protected void disengageValue_() { + for (String listName : this.listNames) { + this.value.removeListChangeListener(listName, this.valueListListener); + } + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValuePropertyAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValuePropertyAdapter.java new file mode 100644 index 0000000000..5fc1714744 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValuePropertyAdapter.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Arrays; + +import org.eclipse.jpt.utility.internal.model.Model; +import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; + +/** + * Extend ValueAspectAdapter to listen to one or more + * properties of the value in the wrapped value model. + */ +public class ValuePropertyAdapter<T extends Model> + extends ValueAspectAdapter<T> +{ + /** The names of the value's properties that we listen to. */ + protected final String[] propertyNames; + + /** Listener that listens to the value. */ + protected final PropertyChangeListener valuePropertyListener; + + + // ********** constructors ********** + + /** + * Construct an adapter for the specified value properties. + */ + public ValuePropertyAdapter(WritablePropertyValueModel<T> valueHolder, String... propertyNames) { + super(valueHolder); + this.propertyNames = propertyNames; + this.valuePropertyListener = this.buildValuePropertyListener(); + } + + + // ********** initialization ********** + + protected PropertyChangeListener buildValuePropertyListener() { + return new PropertyChangeListener() { + public void propertyChanged(PropertyChangeEvent e) { + ValuePropertyAdapter.this.valueAspectChanged(); + } + @Override + public String toString() { + return "value property listener: " + Arrays.asList(ValuePropertyAdapter.this.propertyNames); + } + }; + } + + + // ********** behavior ********** + + @Override + protected void engageValue_() { + for (String propertyName : this.propertyNames) { + this.value.addPropertyChangeListener(propertyName, this.valuePropertyListener); + } + } + + @Override + protected void disengageValue_() { + for (String propertyName : this.propertyNames) { + this.value.removePropertyChangeListener(propertyName, this.valuePropertyListener); + } + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueStateAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueStateAdapter.java new file mode 100644 index 0000000000..b127dbcc69 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueStateAdapter.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import org.eclipse.jpt.utility.internal.model.Model; +import org.eclipse.jpt.utility.internal.model.event.StateChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.StateChangeListener; + +/** + * Extend ValueAspectAdapter to listen to the + * "state" of the value in the wrapped value model. + */ +public class ValueStateAdapter<T extends Model> + extends ValueAspectAdapter<T> +{ + /** Listener that listens to value. */ + protected final StateChangeListener valueStateListener; + + + // ********** constructors ********** + + /** + * Construct an adapter for the value state. + */ + public ValueStateAdapter(WritablePropertyValueModel<T> valueHolder) { + super(valueHolder); + this.valueStateListener = this.buildValueStateListener(); + } + + + // ********** initialization ********** + + protected StateChangeListener buildValueStateListener() { + return new StateChangeListener() { + public void stateChanged(StateChangeEvent e) { + ValueStateAdapter.this.valueAspectChanged(); + } + @Override + public String toString() { + return "value state listener"; + } + }; + } + + + // ********** behavior ********** + + @Override + protected void engageValue_() { + this.value.addStateChangeListener(this.valueStateListener); + } + + @Override + protected void disengageValue_() { + this.value.removeStateChangeListener(this.valueStateListener); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueTreeAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueTreeAdapter.java new file mode 100644 index 0000000000..41e3148c2a --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueTreeAdapter.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2008 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +import java.util.Arrays; + +import org.eclipse.jpt.utility.internal.model.Model; +import org.eclipse.jpt.utility.internal.model.event.TreeChangeEvent; +import org.eclipse.jpt.utility.internal.model.listener.TreeChangeListener; + +/** + * Extend ValueAspectAdapter to listen to one or more + * tree aspects of the value in the wrapped value model. + */ +public class ValueTreeAdapter<T extends Model> + extends ValueAspectAdapter<T> +{ + /** The names of the value's trees that we listen to. */ + protected final String[] treeNames; + + /** Listener that listens to the value. */ + protected final TreeChangeListener valueTreeListener; + + + // ********** constructors ********** + + /** + * Construct an adapter for the specified value trees. + */ + public ValueTreeAdapter(WritablePropertyValueModel<T> valueHolder, String... treeNames) { + super(valueHolder); + this.treeNames = treeNames; + this.valueTreeListener = this.buildValueTreeListener(); + } + + + // ********** initialization ********** + + protected TreeChangeListener buildValueTreeListener() { + return new TreeChangeListener() { + public void nodeAdded(TreeChangeEvent event) { + ValueTreeAdapter.this.valueAspectChanged(); + } + public void nodeRemoved(TreeChangeEvent event) { + ValueTreeAdapter.this.valueAspectChanged(); + } + public void treeCleared(TreeChangeEvent event) { + ValueTreeAdapter.this.valueAspectChanged(); + } + public void treeChanged(TreeChangeEvent event) { + ValueTreeAdapter.this.valueAspectChanged(); + } + @Override + public String toString() { + return "value tree listener: " + Arrays.asList(ValueTreeAdapter.this.treeNames); + } + }; + } + + + // ********** behavior ********** + + @Override + protected void engageValue_() { + for (String treeName : this.treeNames) { + this.value.addTreeChangeListener(treeName, this.valueTreeListener); + } + } + + @Override + protected void disengageValue_() { + for (String treeName : this.treeNames) { + this.value.removeTreeChangeListener(treeName, this.valueTreeListener); + } + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/WritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/WritablePropertyValueModel.java new file mode 100644 index 0000000000..91e819a3d0 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/WritablePropertyValueModel.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.model.value; + +/** + * Extend ValueModel to allow the setting of the property's value. + */ +public interface WritablePropertyValueModel<T> + extends PropertyValueModel<T> +{ + + /** + * Set the value and fire a property change notification. + * @see PropertyValueModel#VALUE + */ + void setValue(T value); + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencePropertyValueModel.java index 2870c29412..c94a3758eb 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencePropertyValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencePropertyValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -17,9 +17,9 @@ import org.eclipse.jpt.utility.internal.BidiStringConverter; import org.eclipse.jpt.utility.internal.model.listener.ChangeListener; import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; import org.eclipse.jpt.utility.internal.model.value.AspectAdapter; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.StaticPropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ReadOnlyPropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This adapter wraps a Preference and converts it into a PropertyValueModel. @@ -44,8 +44,8 @@ import org.eclipse.jpt.utility.internal.model.value.ValueModel; * rely on that event to keep our internally cached value in synch. */ public class PreferencePropertyValueModel<P> - extends AspectAdapter - implements PropertyValueModel + extends AspectAdapter<Preferences> + implements WritablePropertyValueModel<P> { /** The key to the preference we use for the value. */ protected final String key; @@ -95,7 +95,7 @@ public class PreferencePropertyValueModel<P> * the specified default value for the preference. */ public PreferencePropertyValueModel(Preferences preferences, String key, P defaultValue, BidiStringConverter<P> converter) { - this(new ReadOnlyPropertyValueModel(preferences), key, defaultValue, converter); + this(new StaticPropertyValueModel<Preferences>(preferences), key, defaultValue, converter); } /** @@ -128,7 +128,7 @@ public class PreferencePropertyValueModel<P> * Construct an adapter for the specified preference. * The default value of the preference will be null. */ - public PreferencePropertyValueModel(ValueModel preferencesHolder, String key) { + public PreferencePropertyValueModel(PropertyValueModel<? extends Preferences> preferencesHolder, String key) { this(preferencesHolder, key, null); } @@ -136,7 +136,7 @@ public class PreferencePropertyValueModel<P> * Construct an adapter for the specified preference with * the specified default value for the preference. */ - public PreferencePropertyValueModel(ValueModel preferencesHolder, String key, P defaultValue) { + public PreferencePropertyValueModel(PropertyValueModel<? extends Preferences> preferencesHolder, String key, P defaultValue) { this(preferencesHolder, key, defaultValue, BidiStringConverter.Default.<P>instance()); } @@ -144,7 +144,7 @@ public class PreferencePropertyValueModel<P> * Construct an adapter for the specified preference with * the specified default value for the preference. */ - public PreferencePropertyValueModel(ValueModel preferencesHolder, String key, P defaultValue, BidiStringConverter<P> converter) { + public PreferencePropertyValueModel(PropertyValueModel<? extends Preferences> preferencesHolder, String key, P defaultValue, BidiStringConverter<P> converter) { super(preferencesHolder); this.key = key; this.defaultValue = defaultValue; @@ -180,23 +180,17 @@ public class PreferencePropertyValueModel<P> * Return the cached (converted) value. */ @Override - public synchronized Object value() { + public synchronized P value() { return this.value; } // ********** PropertyValueModel implementation ********** - // TODO combine these methods when PropertyValueModel is parameterized - @SuppressWarnings("unchecked") - public synchronized void setValue(Object value) { - this.setValue2((P) value); - } - /** * Set the cached value, then set the appropriate preference value. */ - protected void setValue2(P value) { + public synchronized void setValue(P value) { if (this.hasNoListeners()) { return; // no changes allowed when we have no listeners } @@ -234,15 +228,15 @@ public class PreferencePropertyValueModel<P> } @Override - protected void engageNonNullSubject() { - ((Preferences) this.subject).addPreferenceChangeListener(this.preferenceChangeListener); + protected void engageSubject_() { + this.subject.addPreferenceChangeListener(this.preferenceChangeListener); this.value = this.buildValue(); } @Override - protected void disengageNonNullSubject() { + protected void disengageSubject_() { try { - ((Preferences) this.subject).removePreferenceChangeListener(this.preferenceChangeListener); + this.subject.removePreferenceChangeListener(this.preferenceChangeListener); } catch (IllegalStateException ex) { // for some odd reason, we are not allowed to remove a listener from a "dead" // preferences node; so handle the exception that gets thrown here @@ -270,7 +264,7 @@ public class PreferencePropertyValueModel<P> /** * Return the preference's key. */ - public String getKey() { + public String key() { return this.key; } @@ -290,7 +284,7 @@ public class PreferencePropertyValueModel<P> * At this point we can be sure that the subject is not null. */ protected P buildValue_() { - return this.convertToObject(((Preferences) this.subject).get(this.key, this.convertToString(this.defaultValue))); + return this.convertToObject(this.subject.get(this.key, this.convertToString(this.defaultValue))); } /** @@ -298,7 +292,7 @@ public class PreferencePropertyValueModel<P> * At this point we can be sure that the subject is not null. */ protected void setValue_(P value) { - ((Preferences) this.subject).put(this.key, this.convertToString(value)); + this.subject.put(this.key, this.convertToString(value)); } /** diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java index a0a87ddbac..e30c0239be 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -22,21 +22,21 @@ import org.eclipse.jpt.utility.internal.model.listener.ChangeListener; import org.eclipse.jpt.utility.internal.model.listener.CollectionChangeListener; import org.eclipse.jpt.utility.internal.model.value.AspectAdapter; import org.eclipse.jpt.utility.internal.model.value.CollectionValueModel; -import org.eclipse.jpt.utility.internal.model.value.ReadOnlyPropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; +import org.eclipse.jpt.utility.internal.model.value.StaticPropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; /** * This adapter wraps a Preferences node and converts its preferences into a * CollectionValueModel of PreferencePropertyValueModels. It listens for * "preference" changes and converts them into VALUE collection changes. */ -public class PreferencesCollectionValueModel - extends AspectAdapter - implements CollectionValueModel +public class PreferencesCollectionValueModel<P> + extends AspectAdapter<Preferences> + implements CollectionValueModel<PreferencePropertyValueModel<P>> { /** Cache the current preferences, stored in models and keyed by name. */ - protected final HashMap<String, PreferencePropertyValueModel> preferences; + protected final HashMap<String, PreferencePropertyValueModel<P>> preferences; /** A listener that listens to the preferences node for added or removed preferences. */ protected final PreferenceChangeListener preferenceChangeListener; @@ -48,15 +48,15 @@ public class PreferencesCollectionValueModel * Construct an adapter for the specified preferences node. */ public PreferencesCollectionValueModel(Preferences preferences) { - this(new ReadOnlyPropertyValueModel(preferences)); + this(new StaticPropertyValueModel<Preferences>(preferences)); } /** * Construct an adapter for the specified preferences node. */ - public PreferencesCollectionValueModel(ValueModel preferencesHolder) { + public PreferencesCollectionValueModel(PropertyValueModel<? extends Preferences> preferencesHolder) { super(preferencesHolder); - this.preferences = new HashMap<String, PreferencePropertyValueModel>(); + this.preferences = new HashMap<String, PreferencePropertyValueModel<P>>(); this.preferenceChangeListener = this.buildPreferenceChangeListener(); } @@ -85,7 +85,7 @@ public class PreferencesCollectionValueModel /** * Return an iterator on the preference models. */ - public synchronized Iterator<PreferencePropertyValueModel> iterator() { + public synchronized Iterator<PreferencePropertyValueModel<P>> iterator() { return this.preferences.values().iterator(); } @@ -122,18 +122,18 @@ public class PreferencesCollectionValueModel } @Override - protected void engageNonNullSubject() { - ((Preferences) this.subject).addPreferenceChangeListener(this.preferenceChangeListener); - for (Iterator<PreferencePropertyValueModel> stream = this.preferenceModels(); stream.hasNext(); ) { - PreferencePropertyValueModel preferenceModel = stream.next(); - this.preferences.put(preferenceModel.getKey(), preferenceModel); + protected void engageSubject_() { + this.subject.addPreferenceChangeListener(this.preferenceChangeListener); + for (Iterator<PreferencePropertyValueModel<P>> stream = this.preferenceModels(); stream.hasNext(); ) { + PreferencePropertyValueModel<P> preferenceModel = stream.next(); + this.preferences.put(preferenceModel.key(), preferenceModel); } } @Override - protected void disengageNonNullSubject() { + protected void disengageSubject_() { try { - ((Preferences) this.subject).removePreferenceChangeListener(this.preferenceChangeListener); + this.subject.removePreferenceChangeListener(this.preferenceChangeListener); } catch (IllegalStateException ex) { // for some odd reason, we are not allowed to remove a listener from a "dead" // preferences node; so handle the exception that gets thrown here @@ -160,16 +160,16 @@ public class PreferencesCollectionValueModel * Return an iterator on the preference models. * At this point we can be sure that the subject is not null. */ - protected Iterator<PreferencePropertyValueModel> preferenceModels() { + protected Iterator<PreferencePropertyValueModel<P>> preferenceModels() { String[] keys; try { - keys = ((Preferences) this.subject).keys(); + keys = this.subject.keys(); } catch (BackingStoreException ex) { throw new RuntimeException(ex); } - return new TransformationIterator<String, PreferencePropertyValueModel>(new ArrayIterator<String>(keys)) { + return new TransformationIterator<String, PreferencePropertyValueModel<P>>(new ArrayIterator<String>(keys)) { @Override - protected PreferencePropertyValueModel transform(String key) { + protected PreferencePropertyValueModel<P> transform(String key) { return PreferencesCollectionValueModel.this.buildPreferenceModel(key); } }; @@ -179,18 +179,18 @@ public class PreferencesCollectionValueModel * Override this method to tweak the model used to wrap the * specified preference (e.g. to customize the model's converter). */ - protected PreferencePropertyValueModel buildPreferenceModel(String key) { - return new PreferencePropertyValueModel(this.subjectHolder, key); + protected PreferencePropertyValueModel<P> buildPreferenceModel(String key) { + return new PreferencePropertyValueModel<P>(this.subjectHolder, key); } protected synchronized void preferenceChanged(String key, String newValue) { if (newValue == null) { // a preference was removed - PreferencePropertyValueModel preferenceModel = this.preferences.remove(key); + PreferencePropertyValueModel<P> preferenceModel = this.preferences.remove(key); this.fireItemRemoved(VALUES, preferenceModel); } else if ( ! this.preferences.containsKey(key)) { // a preference was added - PreferencePropertyValueModel preferenceModel = this.buildPreferenceModel(key); + PreferencePropertyValueModel<P> preferenceModel = this.buildPreferenceModel(key); this.preferences.put(key, preferenceModel); this.fireItemAdded(VALUES, preferenceModel); } else { diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/AbstractTreeModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/AbstractTreeModel.java index 725ed6acc9..b16f57df22 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/AbstractTreeModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/AbstractTreeModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -55,7 +55,7 @@ public abstract class AbstractTreeModel * (There seems to be a pattern of making this type of method public; * although it should probably be protected....) */ - public TreeModelListener[] getTreeModelListeners() { + public TreeModelListener[] treeModelListeners() { return this.listenerList.getListeners(TreeModelListener.class); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/CheckBoxModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/CheckBoxModelAdapter.java index 23bf3b68d8..6b669adb6a 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/CheckBoxModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/CheckBoxModelAdapter.java @@ -9,7 +9,7 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value.swing; -import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; /** * This javax.swing.ButtonModel can be used to keep a listener @@ -28,7 +28,7 @@ public class CheckBoxModelAdapter /** * Constructor - the boolean holder is required. */ - public CheckBoxModelAdapter(PropertyValueModel booleanHolder, boolean defaultValue) { + public CheckBoxModelAdapter(WritablePropertyValueModel<Boolean> booleanHolder, boolean defaultValue) { super(booleanHolder, defaultValue); } @@ -36,7 +36,7 @@ public class CheckBoxModelAdapter * Constructor - the boolean holder is required. * The default value will be false. */ - public CheckBoxModelAdapter(PropertyValueModel booleanHolder) { + public CheckBoxModelAdapter(WritablePropertyValueModel<Boolean> booleanHolder) { super(booleanHolder); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ColumnAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ColumnAdapter.java index 62bcde0692..f61e26b2ef 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ColumnAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ColumnAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -9,7 +9,7 @@ ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value.swing; -import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; /** @@ -22,28 +22,28 @@ public interface ColumnAdapter { * Return the number of columns in the table. * Typically this is static. */ - int getColumnCount(); + int columnCount(); /** * Return the name of the specified column. */ - String getColumnName(int index); + String columnName(int index); /** * Return the class of the specified column. */ - Class<?> getColumnClass(int index); + Class<?> columnClass(int index); /** * Return whether the specified column is editable. * Typically this is the same for every row. */ - boolean isColumnEditable(int index); + boolean columnIsEditable(int index); /** * Return the cell models for the specified subject * that corresponds to a single row in the table. */ - PropertyValueModel[] cellModels(Object subject); + WritablePropertyValueModel<Object>[] cellModels(Object subject); }
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ComboBoxModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ComboBoxModelAdapter.java index 3bf1c27b3c..f09e4a3a90 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ComboBoxModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ComboBoxModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -17,8 +17,8 @@ import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper; import org.eclipse.jpt.utility.internal.model.value.CollectionValueModel; import org.eclipse.jpt.utility.internal.model.value.ListValueModel; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This javax.swing.ComboBoxModel can be used to keep a ListDataListener @@ -43,7 +43,7 @@ public class ComboBoxModelAdapter extends ListModelAdapter implements ComboBoxModel { - protected final PropertyValueModel selectionHolder; + protected final WritablePropertyValueModel<Object> selectionHolder; protected final PropertyChangeListener selectionListener; @@ -52,7 +52,7 @@ public class ComboBoxModelAdapter /** * Constructor - the list holder and selection holder are required; */ - public ComboBoxModelAdapter(ListValueModel listHolder, PropertyValueModel selectionHolder) { + public ComboBoxModelAdapter(ListValueModel<?> listHolder, WritablePropertyValueModel<Object> selectionHolder) { super(listHolder); if (selectionHolder == null) { throw new NullPointerException(); @@ -64,7 +64,7 @@ public class ComboBoxModelAdapter /** * Constructor - the collection holder and selection holder are required; */ - public ComboBoxModelAdapter(CollectionValueModel collectionHolder, PropertyValueModel selectionHolder) { + public ComboBoxModelAdapter(CollectionValueModel<?> collectionHolder, WritablePropertyValueModel<Object> selectionHolder) { super(collectionHolder); if (selectionHolder == null) { throw new NullPointerException(); @@ -113,7 +113,7 @@ public class ComboBoxModelAdapter @Override protected void engageModel() { super.engageModel(); - this.selectionHolder.addPropertyChangeListener(ValueModel.VALUE, this.selectionListener); + this.selectionHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.selectionListener); } /** @@ -121,7 +121,7 @@ public class ComboBoxModelAdapter */ @Override protected void disengageModel() { - this.selectionHolder.removePropertyChangeListener(ValueModel.VALUE, this.selectionListener); + this.selectionHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.selectionListener); super.disengageModel(); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DateSpinnerModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DateSpinnerModelAdapter.java index 1910a01055..d289b38211 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DateSpinnerModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DateSpinnerModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -19,8 +19,8 @@ import org.eclipse.jpt.utility.internal.StringTools; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This javax.swing.SpinnerDateModel can be used to keep a ChangeListener @@ -46,7 +46,7 @@ public class DateSpinnerModelAdapter private final Date defaultValue; /** A value model on the underlying date. */ - private final PropertyValueModel dateHolder; + private final WritablePropertyValueModel<Object> dateHolder; /** A listener that allows us to synchronize with changes made to the underlying date. */ private final PropertyChangeListener dateChangeListener; @@ -58,14 +58,14 @@ public class DateSpinnerModelAdapter * Constructor - the date holder is required. * The default spinner value is the current date. */ - public DateSpinnerModelAdapter(PropertyValueModel dateHolder) { + public DateSpinnerModelAdapter(WritablePropertyValueModel<Object> dateHolder) { this(dateHolder, new Date()); } /** * Constructor - the date holder and default value are required. */ - public DateSpinnerModelAdapter(PropertyValueModel dateHolder, Date defaultValue) { + public DateSpinnerModelAdapter(WritablePropertyValueModel<Object> dateHolder, Date defaultValue) { this(dateHolder, null, null, Calendar.DAY_OF_MONTH, defaultValue); } @@ -73,14 +73,14 @@ public class DateSpinnerModelAdapter * Constructor - the date holder is required. * The default spinner value is the current date. */ - public DateSpinnerModelAdapter(PropertyValueModel dateHolder, Comparable start, Comparable end, int calendarField) { + public DateSpinnerModelAdapter(WritablePropertyValueModel<Object> dateHolder, Comparable<?> start, Comparable<?> end, int calendarField) { this(dateHolder, start, end, calendarField, new Date()); } /** * Constructor - the date holder is required. */ - public DateSpinnerModelAdapter(PropertyValueModel dateHolder, Comparable start, Comparable end, int calendarField, Date defaultValue) { + public DateSpinnerModelAdapter(WritablePropertyValueModel<Object> dateHolder, Comparable<?> start, Comparable<?> end, int calendarField, Date defaultValue) { super(dateHolder.value() == null ? defaultValue : (Date) dateHolder.value(), start, end, calendarField); this.dateHolder = dateHolder; this.dateChangeListener = this.buildDateChangeListener(); @@ -143,7 +143,7 @@ public class DateSpinnerModelAdapter @Override public void addChangeListener(ChangeListener listener) { if (this.getChangeListeners().length == 0) { - this.dateHolder.addPropertyChangeListener(ValueModel.VALUE, this.dateChangeListener); + this.dateHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.dateChangeListener); this.synchronize(this.dateHolder.value()); } super.addChangeListener(listener); @@ -156,7 +156,7 @@ public class DateSpinnerModelAdapter public void removeChangeListener(ChangeListener listener) { super.removeChangeListener(listener); if (this.getChangeListeners().length == 0) { - this.dateHolder.removePropertyChangeListener(ValueModel.VALUE, this.dateChangeListener); + this.dateHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.dateChangeListener); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DocumentAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DocumentAdapter.java index 6eaba6cf99..48378b66be 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DocumentAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DocumentAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -29,8 +29,8 @@ import org.eclipse.jpt.utility.internal.StringTools; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This javax.swing.text.Document can be used to keep a DocumentListener @@ -51,7 +51,7 @@ public class DocumentAdapter protected final CombinedListener delegateListener; /** A value model on the underlying model string. */ - protected final PropertyValueModel stringHolder; + protected final WritablePropertyValueModel<String> stringHolder; /** A listener that allows us to synchronize with changes made to the underlying model string. */ protected final PropertyChangeListener stringListener; @@ -66,7 +66,7 @@ public class DocumentAdapter * Constructor - the string holder is required. * Wrap the specified document. */ - public DocumentAdapter(PropertyValueModel stringHolder, Document delegate) { + public DocumentAdapter(WritablePropertyValueModel<String> stringHolder, Document delegate) { super(); if (stringHolder == null || delegate == null) { throw new NullPointerException(); @@ -83,7 +83,7 @@ public class DocumentAdapter * Constructor - the string holder is required. * Wrap a plain document. */ - public DocumentAdapter(PropertyValueModel stringHolder) { + public DocumentAdapter(WritablePropertyValueModel<String> stringHolder) { this(stringHolder, new PlainDocument()); } @@ -220,11 +220,11 @@ public class DocumentAdapter // ********** queries ********** - public DocumentListener[] getDocumentListeners() { + public DocumentListener[] documentListeners() { return this.listenerList.getListeners(DocumentListener.class); } - public UndoableEditListener[] getUndoableEditListeners() { + public UndoableEditListener[] undoableEditListeners() { return this.listenerList.getListeners(UndoableEditListener.class); } @@ -257,19 +257,19 @@ public class DocumentAdapter } protected void engageStringHolder() { - this.stringHolder.addPropertyChangeListener(ValueModel.VALUE, this.stringListener); - this.synchronizeDelegate((String) this.stringHolder.value()); + this.stringHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.stringListener); + this.synchronizeDelegate(this.stringHolder.value()); } protected void disengageStringHolder() { - this.stringHolder.removePropertyChangeListener(ValueModel.VALUE, this.stringListener); + this.stringHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.stringListener); } protected void delegateChangedUpdate(DocumentEvent e) { // no need to lazy-initialize the event; // we wouldn't get here if we did not have listeners... DocumentEvent ee = new InternalDocumentEvent(this, e); - DocumentListener[] listeners = this.getDocumentListeners(); + DocumentListener[] listeners = this.documentListeners(); for (int i = listeners.length; i-- > 0; ) { listeners[i].changedUpdate(ee); } @@ -279,7 +279,7 @@ public class DocumentAdapter // no need to lazy-initialize the event; // we wouldn't get here if we did not have listeners... DocumentEvent ee = new InternalDocumentEvent(this, e); - DocumentListener[] listeners = this.getDocumentListeners(); + DocumentListener[] listeners = this.documentListeners(); for (int i = listeners.length; i-- > 0; ) { listeners[i].insertUpdate(ee); } @@ -289,7 +289,7 @@ public class DocumentAdapter // no need to lazy-initialize the event; // we wouldn't get here if we did not have listeners... DocumentEvent ee = new InternalDocumentEvent(this, e); - DocumentListener[] listeners = this.getDocumentListeners(); + DocumentListener[] listeners = this.documentListeners(); for (int i = listeners.length; i-- > 0; ) { listeners[i].removeUpdate(ee); } @@ -299,7 +299,7 @@ public class DocumentAdapter // no need to lazy-initialize the event; // we wouldn't get here if we did not have listeners... UndoableEditEvent ee = new UndoableEditEvent(this, e.getEdit()); - UndoableEditListener[] listeners = this.getUndoableEditListeners(); + UndoableEditListener[] listeners = this.undoableEditListeners(); for (int i = listeners.length; i-- > 0; ) { listeners[i].undoableEditHappened(ee); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListModelAdapter.java index b83d5ca3dd..5e691b92a3 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -33,7 +33,7 @@ public class ListModelAdapter extends AbstractListModel { /** A value model on the underlying model list. */ - protected ListValueModel listHolder; + protected ListValueModel<?> listHolder; /** * Cache the size of the list for "dramatic" changes. @@ -59,7 +59,7 @@ public class ListModelAdapter /** * Constructor - the list holder is required. */ - public ListModelAdapter(ListValueModel listHolder) { + public ListModelAdapter(ListValueModel<?> listHolder) { this(); this.setModel(listHolder); } @@ -67,7 +67,7 @@ public class ListModelAdapter /** * Constructor - the collection holder is required. */ - public ListModelAdapter(CollectionValueModel collectionHolder) { + public ListModelAdapter(CollectionValueModel<?> collectionHolder) { this(); this.setModel(collectionHolder); } @@ -147,14 +147,14 @@ public class ListModelAdapter /** * Return the underlying list model. */ - public ListValueModel getModel() { + public ListValueModel<?> model() { return this.listHolder; } /** * Set the underlying list model. */ - public void setModel(ListValueModel listHolder) { + public void setModel(ListValueModel<?> listHolder) { if (listHolder == null) { throw new NullPointerException(); } @@ -172,7 +172,8 @@ public class ListModelAdapter /** * Set the underlying collection model. */ - public void setModel(CollectionValueModel collectionHolder) { + @SuppressWarnings("unchecked") + public void setModel(CollectionValueModel<?> collectionHolder) { this.setModel(new CollectionListValueModelAdapter(collectionHolder)); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListSpinnerModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListSpinnerModelAdapter.java index 9923074181..37a750001d 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListSpinnerModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListSpinnerModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -19,8 +19,8 @@ import org.eclipse.jpt.utility.internal.StringTools; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This javax.swing.SpinnerListModel can be used to keep a ChangeListener @@ -51,7 +51,7 @@ public class ListSpinnerModelAdapter private final Object defaultValue; /** A value model on the underlying value. */ - private final PropertyValueModel valueHolder; + private final WritablePropertyValueModel<Object> valueHolder; /** A listener that allows us to synchronize with changes made to the underlying value. */ private final PropertyChangeListener valueChangeListener; @@ -63,14 +63,14 @@ public class ListSpinnerModelAdapter * Constructor - the value holder is required. * Use the model value itself as the default spinner value. */ - public ListSpinnerModelAdapter(PropertyValueModel valueHolder) { + public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder) { this(valueHolder, valueHolder.value()); } /** * Constructor - the value holder is required. */ - public ListSpinnerModelAdapter(PropertyValueModel valueHolder, Object defaultValue) { + public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object defaultValue) { this(valueHolder, new Object[] {defaultValue}, defaultValue); } @@ -78,14 +78,14 @@ public class ListSpinnerModelAdapter * Constructor - the value holder is required. * Use the first item in the list of values as the default spinner value. */ - public ListSpinnerModelAdapter(PropertyValueModel valueHolder, Object[] values) { + public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object[] values) { this(valueHolder, values, values[0]); } /** * Constructor - the value holder is required. */ - public ListSpinnerModelAdapter(PropertyValueModel valueHolder, Object[] values, Object defaultValue) { + public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object[] values, Object defaultValue) { this(valueHolder, Arrays.asList(values), defaultValue); } @@ -93,14 +93,14 @@ public class ListSpinnerModelAdapter * Constructor - the value holder is required. * Use the first item in the list of values as the default spinner value. */ - public ListSpinnerModelAdapter(PropertyValueModel valueHolder, List values) { + public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, List<Object> values) { this(valueHolder, values, values.get(0)); } /** * Constructor - the value holder is required. */ - public ListSpinnerModelAdapter(PropertyValueModel valueHolder, List values, Object defaultValue) { + public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, List<Object> values, Object defaultValue) { super(values); this.valueHolder = valueHolder; this.valueChangeListener = this.buildValueChangeListener(); @@ -163,7 +163,7 @@ public class ListSpinnerModelAdapter @Override public void addChangeListener(ChangeListener listener) { if (this.getChangeListeners().length == 0) { - this.valueHolder.addPropertyChangeListener(ValueModel.VALUE, this.valueChangeListener); + this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener); this.synchronize(this.valueHolder.value()); } super.addChangeListener(listener); @@ -176,7 +176,7 @@ public class ListSpinnerModelAdapter public void removeChangeListener(ChangeListener listener) { super.removeChangeListener(listener); if (this.getChangeListeners().length == 0) { - this.valueHolder.removePropertyChangeListener(ValueModel.VALUE, this.valueChangeListener); + this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/NumberSpinnerModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/NumberSpinnerModelAdapter.java index d7a49e85b5..86820054ac 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/NumberSpinnerModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/NumberSpinnerModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -16,8 +16,8 @@ import org.eclipse.jpt.utility.internal.StringTools; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This javax.swing.SpinnerNumberModel can be used to keep a ChangeListener @@ -43,7 +43,7 @@ public class NumberSpinnerModelAdapter private final Number defaultValue; /** A value model on the underlying number. */ - private final PropertyValueModel numberHolder; + private final WritablePropertyValueModel<Number> numberHolder; /** * A listener that allows us to synchronize with @@ -59,7 +59,7 @@ public class NumberSpinnerModelAdapter * The default spinner value is zero. * The step size is one. */ - public NumberSpinnerModelAdapter(PropertyValueModel numberHolder) { + public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder) { this(numberHolder, 0); } @@ -67,7 +67,7 @@ public class NumberSpinnerModelAdapter * Constructor - the number holder is required. * The step size is one. */ - public NumberSpinnerModelAdapter(PropertyValueModel numberHolder, int defaultValue) { + public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, int defaultValue) { this(numberHolder, null, null, new Integer(1), new Integer(defaultValue)); } @@ -75,14 +75,14 @@ public class NumberSpinnerModelAdapter * Constructor - the number holder is required. * Use the minimum value as the default spinner value. */ - public NumberSpinnerModelAdapter(PropertyValueModel numberHolder, int minimum, int maximum, int stepSize) { + public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, int minimum, int maximum, int stepSize) { this(numberHolder, minimum, maximum, stepSize, minimum); } /** * Constructor - the number holder is required. */ - public NumberSpinnerModelAdapter(PropertyValueModel numberHolder, int minimum, int maximum, int stepSize, int defaultValue) { + public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, int minimum, int maximum, int stepSize, int defaultValue) { this(numberHolder, new Integer(minimum), new Integer(maximum), new Integer(stepSize), new Integer(defaultValue)); } @@ -90,21 +90,21 @@ public class NumberSpinnerModelAdapter * Constructor - the number holder is required. * Use the minimum value as the default spinner value. */ - public NumberSpinnerModelAdapter(PropertyValueModel numberHolder, double value, double minimum, double maximum, double stepSize) { + public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, double value, double minimum, double maximum, double stepSize) { this(numberHolder, value, minimum, maximum, stepSize, minimum); } /** * Constructor - the number holder is required. */ - public NumberSpinnerModelAdapter(PropertyValueModel numberHolder, double value, double minimum, double maximum, double stepSize, double defaultValue) { + public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, double value, double minimum, double maximum, double stepSize, double defaultValue) { this(numberHolder, new Double(minimum), new Double(maximum), new Double(stepSize), new Double(defaultValue)); } /** * Constructor - the number holder is required. */ - public NumberSpinnerModelAdapter(PropertyValueModel numberHolder, Comparable minimum, Comparable maximum, Number stepSize, Number defaultValue) { + public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, Comparable<?> minimum, Comparable<?> maximum, Number stepSize, Number defaultValue) { super(numberHolder.value() == null ? defaultValue : (Number) numberHolder.value(), minimum, maximum, stepSize); this.numberHolder = numberHolder; this.numberChangeListener = this.buildNumberChangeListener(); @@ -158,7 +158,7 @@ public class NumberSpinnerModelAdapter @Override public void setValue(Object value) { super.setValue(value); - this.numberHolder.setValue(value); + this.numberHolder.setValue((Number) value); } /** @@ -167,7 +167,7 @@ public class NumberSpinnerModelAdapter @Override public void addChangeListener(ChangeListener listener) { if (this.getChangeListeners().length == 0) { - this.numberHolder.addPropertyChangeListener(ValueModel.VALUE, this.numberChangeListener); + this.numberHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.numberChangeListener); this.synchronize(this.numberHolder.value()); } super.addChangeListener(listener); @@ -180,7 +180,7 @@ public class NumberSpinnerModelAdapter public void removeChangeListener(ChangeListener listener) { super.removeChangeListener(listener); if (this.getChangeListeners().length == 0) { - this.numberHolder.removePropertyChangeListener(ValueModel.VALUE, this.numberChangeListener); + this.numberHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.numberChangeListener); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ObjectListSelectionModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ObjectListSelectionModel.java index a02eb1af55..a1d0437682 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ObjectListSelectionModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ObjectListSelectionModel.java @@ -1,23 +1,22 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. - * + * * Contributors: * Oracle - initial API and implementation ******************************************************************************/ package org.eclipse.jpt.utility.internal.model.value.swing; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; - import javax.swing.DefaultListSelectionModel; import javax.swing.ListModel; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionListener; - import org.eclipse.jpt.utility.internal.CollectionTools; /** @@ -71,7 +70,7 @@ public class ObjectListSelectionModel * Typically, the selection does not need to be cleared when the * contents of the list have changed. Most of the time this just * means an item has changed in a way that affects its display string - * or icon. We typically only use the class for edits involving + * or icon. We typically only use the class for edits involving * single selection. * A subclass can override this method if the selection * should be cleared because a change could mean the selection is invalid. @@ -108,15 +107,15 @@ public class ObjectListSelectionModel protected boolean hasNoListSelectionListeners() { // private-protected return this.getListSelectionListeners().length == 0; } - + /** * Return the list model referenced by the list selection model. */ - public ListModel getListModel() { + public ListModel listModel() { return this.listModel; } - public int getSelectedValuesSize() { + public int selectedValuesSize() { int min = this.getMinSelectionIndex(); int max = this.getMaxSelectionIndex(); @@ -125,7 +124,7 @@ public class ObjectListSelectionModel } int n = 0; - int count = this.getListModel().getSize(); + int count = this.listModel().getSize(); for (int i = min; i <= max; i++) { if (this.isSelectedIndex(i) && (i < count)) { n++; @@ -138,21 +137,21 @@ public class ObjectListSelectionModel * Return the first selected value. * Return null if the selection is empty. */ - public Object getSelectedValue() { + public Object selectedValue() { int index = this.getMinSelectionIndex(); if (index == -1) { return null; } - if (this.getListModel().getSize() <= index) { + if (this.listModel().getSize() <= index) { return null; } - return this.getListModel().getElementAt(index); + return this.listModel().getElementAt(index); } /** * Return an array of the selected values. */ - public Object[] getSelectedValues() { + public Object[] selectedValues() { int min = this.getMinSelectionIndex(); int max = this.getMaxSelectionIndex(); @@ -163,10 +162,10 @@ public class ObjectListSelectionModel int maxSize = (max - min) + 1; Object[] temp = new Object[maxSize]; int n = 0; - int count = this.getListModel().getSize(); + int count = this.listModel().getSize(); for (int i = min; i <= max; i++) { if (this.isSelectedIndex(i) && (i < count)) { - temp[n++] = this.getListModel().getElementAt(i); + temp[n++] = this.listModel().getElementAt(i); } } if (n == maxSize) { @@ -180,6 +179,38 @@ public class ObjectListSelectionModel } /** + * Return an array of the selected indices in ordered. + */ + public int[] selectedIndices() { + int min = this.getMinSelectionIndex(); + int max = this.getMaxSelectionIndex(); + + if ((min < 0) || (max < 0)) { + return new int[0]; + } + + int maxSize = (max - min) + 1; + int[] temp = new int[maxSize]; + int n = 0; + int count = this.listModel().getSize(); + for (int i = min; i <= max; i++) { + if (this.isSelectedIndex(i) && (i < count)) { + temp[n++] = i; + } + } + if (n == maxSize) { + // all the elements in the range were selected + Arrays.sort(temp); + return temp; + } + // only some of the elements in the range were selected + int[] result = new int[n]; + System.arraycopy(temp, 0, result, 0, n); + Arrays.sort(result); + return result; + } + + /** * Set the selected value. */ public void setSelectedValue(Object object) { @@ -190,7 +221,7 @@ public class ObjectListSelectionModel * Set the current set of selected objects to the specified objects. * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int) */ - public void setSelectedValues(Iterator objects) { + public void setSelectedValues(Iterator<?> objects) { this.setValueIsAdjusting(true); this.clearSelection(); this.addSelectedValuesInternal(objects); @@ -201,10 +232,10 @@ public class ObjectListSelectionModel * Set the current set of selected objects to the specified objects. * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int) */ - public void setSelectedValues(Collection objects) { + public void setSelectedValues(Collection<?> objects) { this.setSelectedValues(objects.iterator()); } - + /** * Set the current set of selected objects to the specified objects. * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int) @@ -225,20 +256,20 @@ public class ObjectListSelectionModel * Add the specified objects to the current set of selected objects. * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int) */ - public void addSelectedValues(Iterator objects) { + public void addSelectedValues(Iterator<?> objects) { this.setValueIsAdjusting(true); this.addSelectedValuesInternal(objects); this.setValueIsAdjusting(false); } - + /** * Add the specified objects to the current set of selected objects. * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int) */ - public void addSelectedValues(Collection objects) { + public void addSelectedValues(Collection<?> objects) { this.addSelectedValues(objects.iterator()); } - + /** * Add the specified objects to the current set of selected objects. * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int) @@ -246,7 +277,7 @@ public class ObjectListSelectionModel public void addSelectedValues(Object[] objects) { this.addSelectedValues(CollectionTools.iterator(objects)); } - + /** * Remove the specified object from the current set of selected objects. * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int) @@ -259,9 +290,9 @@ public class ObjectListSelectionModel * Remove the specified objects from the current set of selected objects. * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int) */ - public void removeSelectedValues(Iterator objects) { + public void removeSelectedValues(Iterator<?> objects) { this.setValueIsAdjusting(true); - ListModel lm = this.getListModel(); + ListModel lm = this.listModel(); int lmSize = lm.getSize(); while (objects.hasNext()) { int index = this.indexOf(objects.next(), lm, lmSize); @@ -269,15 +300,15 @@ public class ObjectListSelectionModel } this.setValueIsAdjusting(false); } - + /** * Remove the specified objects from the current set of selected objects. * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int) */ - public void removeSelectedValues(Collection objects) { + public void removeSelectedValues(Collection<?> objects) { this.removeSelectedValues(objects.iterator()); } - + /** * Remove the specified objects from the current set of selected objects. * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int) @@ -285,7 +316,7 @@ public class ObjectListSelectionModel public void removeSelectedValues(Object[] objects) { this.removeSelectedValues(CollectionTools.iterator(objects)); } - + /** * @see javax.swing.ListSelectionModel#getAnchorSelectionIndex() * Return null if the anchor selection is empty. @@ -295,16 +326,16 @@ public class ObjectListSelectionModel if (index == -1) { return null; } - return this.getListModel().getElementAt(index); + return this.listModel().getElementAt(index); } - + /** * @see javax.swing.ListSelectionModel#setAnchorSelectionIndex(int) */ public void setAnchorSelectedValue(Object object) { this.setAnchorSelectionIndex(this.indexOf(object)); } - + /** * @see javax.swing.ListSelectionModel#getLeadSelectionIndex() * Return null if the lead selection is empty. @@ -314,16 +345,16 @@ public class ObjectListSelectionModel if (index == -1) { return null; } - return this.getListModel().getElementAt(index); + return this.listModel().getElementAt(index); } - + /** * @see javax.swing.ListSelectionModel#setLeadSelectionIndex(int) */ public void setLeadSelectedValue(Object object) { this.setLeadSelectionIndex(this.indexOf(object)); } - + /** * @see javax.swing.ListSelectionModel#getMaxSelectionIndex() * Return null if the max selection is empty. @@ -333,9 +364,9 @@ public class ObjectListSelectionModel if (index == -1) { return null; } - return this.getListModel().getElementAt(index); + return this.listModel().getElementAt(index); } - + /** * @see javax.swing.ListSelectionModel#getMinSelectionIndex() * Return null if the min selection is empty. @@ -345,7 +376,7 @@ public class ObjectListSelectionModel if (index == -1) { return null; } - return this.getListModel().getElementAt(index); + return this.listModel().getElementAt(index); } /** @@ -359,8 +390,8 @@ public class ObjectListSelectionModel * Add the specified objects to the current set of selected objects, * without wrapping the actions in "adjusting" events. */ - private void addSelectedValuesInternal(Iterator objects) { - ListModel lm = this.getListModel(); + private void addSelectedValuesInternal(Iterator<?> objects) { + ListModel lm = this.listModel(); int listModelSize = lm.getSize(); while (objects.hasNext()) { int index = this.indexOf(objects.next(), lm, listModelSize); @@ -373,7 +404,7 @@ public class ObjectListSelectionModel * Return -1 if the object is not in the list model. */ private int indexOf(Object object) { - ListModel lm = this.getListModel(); + ListModel lm = this.listModel(); return this.indexOf(object, lm, lm.getSize()); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/PrimitiveListTreeModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/PrimitiveListTreeModel.java index 4275a11d68..cc3b4f2ac4 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/PrimitiveListTreeModel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/PrimitiveListTreeModel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -49,7 +49,7 @@ public abstract class PrimitiveListTreeModel extends DefaultTreeModel { /** a model on the list of primitives */ - private final ListValueModel listHolder; + private final ListValueModel<?> listHolder; /** a listener that handles the adding, removing, and replacing of the primitives */ private final ListChangeListener listChangeListener; @@ -60,7 +60,7 @@ public abstract class PrimitiveListTreeModel /** * Public constructor - the list holder is required */ - public PrimitiveListTreeModel(ListValueModel listHolder) { + public PrimitiveListTreeModel(ListValueModel<?> listHolder) { super(new DefaultMutableTreeNode(null, true)); // true = the root can have children if (listHolder == null) { throw new NullPointerException(); @@ -144,7 +144,7 @@ public abstract class PrimitiveListTreeModel } private void buildList() { - for (Iterator stream = this.listHolder.iterator(); stream.hasNext(); ) { + for (Iterator<?> stream = this.listHolder.iterator(); stream.hasNext(); ) { this.addPrimitive(stream.next()); } } @@ -193,7 +193,7 @@ public abstract class PrimitiveListTreeModel public void itemsAdded(ListChangeEvent e) { int i = e.index(); - for (ListIterator stream = e.items(); stream.hasNext(); ) { + for (ListIterator<?> stream = e.items(); stream.hasNext(); ) { PrimitiveListTreeModel.this.insertPrimitive(i++, stream.next()); } } @@ -206,7 +206,7 @@ public abstract class PrimitiveListTreeModel public void itemsReplaced(ListChangeEvent e) { int i = e.index(); - for (ListIterator stream = e.items(); stream.hasNext(); ) { + for (ListIterator<?> stream = e.items(); stream.hasNext(); ) { PrimitiveListTreeModel.this.replacePrimitive(i++, stream.next()); } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/RadioButtonModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/RadioButtonModelAdapter.java index 3e1804088d..14e783cb05 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/RadioButtonModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/RadioButtonModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -11,9 +11,9 @@ package org.eclipse.jpt.utility.internal.model.value.swing; import org.eclipse.jpt.utility.internal.BidiFilter; import org.eclipse.jpt.utility.internal.BidiTransformer; -import org.eclipse.jpt.utility.internal.model.value.FilteringPropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.TransformationPropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.FilteringWritablePropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.TransformationWritablePropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; /** * This javax.swing.ButtonModel can be used to keep a listener @@ -35,7 +35,7 @@ public class RadioButtonModelAdapter /** * Constructor - the value holder is required. */ - public RadioButtonModelAdapter(PropertyValueModel valueHolder, Object buttonValue, boolean defaultValue) { + public RadioButtonModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object buttonValue, boolean defaultValue) { super(buildBooleanHolder(valueHolder, buttonValue), defaultValue); } @@ -43,7 +43,7 @@ public class RadioButtonModelAdapter * Constructor - the value holder is required. * The default value will be false. */ - public RadioButtonModelAdapter(PropertyValueModel valueHolder, Object buttonValue) { + public RadioButtonModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object buttonValue) { super(buildBooleanHolder(valueHolder, buttonValue)); } @@ -59,9 +59,9 @@ public class RadioButtonModelAdapter * value is set to true, the wrapper will set the value holder's * value to the button value. */ - public static PropertyValueModel buildBooleanHolder(PropertyValueModel valueHolder, Object buttonValue) { - PropertyValueModel filteringPVM = new FilteringPropertyValueModel(valueHolder, new RadioButtonFilter(buttonValue)); - return new TransformationPropertyValueModel(filteringPVM, new RadioButtonTransformer(buttonValue)); + public static WritablePropertyValueModel<Boolean> buildBooleanHolder(WritablePropertyValueModel<Object> valueHolder, Object buttonValue) { + WritablePropertyValueModel<Object> filteringPVM = new FilteringWritablePropertyValueModel<Object>(valueHolder, new RadioButtonFilter(buttonValue)); + return new TransformationWritablePropertyValueModel<Object, Boolean>(filteringPVM, new RadioButtonTransformer(buttonValue)); } @@ -91,7 +91,7 @@ public class RadioButtonModelAdapter * This filter will only pass through a new value to the wrapped * value holder when it matches the configured button value. */ - public static class RadioButtonFilter implements BidiFilter { + public static class RadioButtonFilter implements BidiFilter<Object> { private Object buttonValue; public RadioButtonFilter(Object buttonValue) { @@ -120,7 +120,7 @@ public class RadioButtonModelAdapter * This transformer will convert the wrapped value to Boolean.TRUE * when it matches the configured button value. */ - public static class RadioButtonTransformer implements BidiTransformer { + public static class RadioButtonTransformer implements BidiTransformer<Object, Boolean> { private Object buttonValue; public RadioButtonTransformer(Object buttonValue) { @@ -134,7 +134,7 @@ public class RadioButtonModelAdapter * but if it is null simply pass it through because it will cause the * button model's default value to be used */ - public Object transform(Object value) { + public Boolean transform(Object value) { return (value == null) ? null : Boolean.valueOf(value == this.buttonValue); } @@ -142,8 +142,8 @@ public class RadioButtonModelAdapter * if the new value is true, pass through the our button value; * otherwise pass through null */ - public Object reverseTransform(Object value) { - return (((Boolean) value).booleanValue()) ? this.buttonValue : null; + public Object reverseTransform(Boolean value) { + return (value.booleanValue()) ? this.buttonValue : null; } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/SpinnerModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/SpinnerModelAdapter.java index 5cfbd0e6fe..b6cfdebc1b 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/SpinnerModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/SpinnerModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -19,8 +19,8 @@ import org.eclipse.jpt.utility.internal.StringTools; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This javax.swing.SpinnerModel can be used to keep a ChangeListener @@ -46,7 +46,7 @@ public class SpinnerModelAdapter protected final ChangeListener delegateListener; /** A value model on the underlying value. */ - protected final PropertyValueModel valueHolder; + protected final WritablePropertyValueModel<Object> valueHolder; /** A listener that allows us to synchronize with changes made to the underlying value. */ protected final PropertyChangeListener valueListener; @@ -57,7 +57,7 @@ public class SpinnerModelAdapter /** * Constructor - the value holder and delegate are required. */ - public SpinnerModelAdapter(PropertyValueModel valueHolder, SpinnerModel delegate) { + public SpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, SpinnerModel delegate) { super(); if (valueHolder == null || delegate == null) { throw new NullPointerException(); @@ -74,7 +74,7 @@ public class SpinnerModelAdapter * Constructor - the value holder is required. * This will wrap a simple number spinner model. */ - public SpinnerModelAdapter(PropertyValueModel valueHolder) { + public SpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder) { this(valueHolder, new SpinnerNumberModel()); } @@ -189,12 +189,12 @@ public class SpinnerModelAdapter } protected void engageValueHolder() { - this.valueHolder.addPropertyChangeListener(ValueModel.VALUE, this.valueListener); + this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueListener); this.synchronizeDelegate(this.valueHolder.value()); } protected void disengageValueHolder() { - this.valueHolder.removePropertyChangeListener(ValueModel.VALUE, this.valueListener); + this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueListener); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TableModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TableModelAdapter.java index ab5ad28bfe..905d26480e 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TableModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TableModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -25,8 +25,8 @@ import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeList import org.eclipse.jpt.utility.internal.model.value.CollectionListValueModelAdapter; import org.eclipse.jpt.utility.internal.model.value.CollectionValueModel; import org.eclipse.jpt.utility.internal.model.value.ListValueModel; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This TableModel can be used to keep a TableModelListener (e.g. a JTable) @@ -59,21 +59,21 @@ import org.eclipse.jpt.utility.internal.model.value.ValueModel; * - 1 cell listener per row * - 1 cell listener per cell */ -public class TableModelAdapter +public class TableModelAdapter<E> extends AbstractTableModel { /** * a list of user objects that are converted to * rows via the column adapter */ - private ListValueModel listHolder; + private ListValueModel<? extends E> listHolder; private final ListChangeListener listChangeListener; /** * each row is an array of cell models */ // declare as ArrayList so we can use #ensureCapacity(int) - private final ArrayList<PropertyValueModel[]> rows; + private final ArrayList<WritablePropertyValueModel<Object>[]> rows; /** * client-supplied adapter that provides with the various column @@ -94,7 +94,7 @@ public class TableModelAdapter * Construct a table model adapter for the specified objects * and adapter. */ - public TableModelAdapter(ListValueModel listHolder, ColumnAdapter columnAdapter) { + public TableModelAdapter(ListValueModel<? extends E> listHolder, ColumnAdapter columnAdapter) { super(); if (listHolder == null) { throw new NullPointerException(); @@ -102,7 +102,7 @@ public class TableModelAdapter this.listHolder = listHolder; this.columnAdapter = columnAdapter; this.listChangeListener = this.buildListChangeListener(); - this.rows = new ArrayList<PropertyValueModel[]>(); + this.rows = new ArrayList<WritablePropertyValueModel<Object>[]>(); this.cellListener = this.buildCellListener(); } @@ -110,8 +110,8 @@ public class TableModelAdapter * Construct a table model adapter for the specified objects * and adapter. */ - public TableModelAdapter(CollectionValueModel collectionHolder, ColumnAdapter columnAdapter) { - this(new CollectionListValueModelAdapter(collectionHolder), columnAdapter); + public TableModelAdapter(CollectionValueModel<? extends E> collectionHolder, ColumnAdapter columnAdapter) { + this(new CollectionListValueModelAdapter<E>(collectionHolder), columnAdapter); } @@ -124,13 +124,13 @@ public class TableModelAdapter protected ListChangeListener buildListChangeListener_() { return new ListChangeListener() { public void itemsAdded(ListChangeEvent e) { - TableModelAdapter.this.addRows(e.index(), e.itemsSize(), e.items()); + TableModelAdapter.this.addRows(e.index(), e.itemsSize(), this.items(e)); } public void itemsRemoved(ListChangeEvent e) { TableModelAdapter.this.removeRows(e.index(), e.itemsSize()); } public void itemsReplaced(ListChangeEvent e) { - TableModelAdapter.this.replaceRows(e.index(), e.items()); + TableModelAdapter.this.replaceRows(e.index(), this.items(e)); } public void itemsMoved(ListChangeEvent e) { TableModelAdapter.this.moveRows(e.targetIndex(), e.sourceIndex(), e.moveLength()); @@ -141,6 +141,13 @@ public class TableModelAdapter public void listChanged(ListChangeEvent e) { TableModelAdapter.this.rebuildTable(); } + /** + * minimize scope of suppressed warnings + */ + @SuppressWarnings("unchecked") + protected Iterator<Object> items(ListChangeEvent event) { + return (Iterator<Object>) event.items(); + } @Override public String toString() { return "list listener"; @@ -148,14 +155,16 @@ public class TableModelAdapter }; } + protected PropertyChangeListener buildCellListener() { return new AWTPropertyChangeListenerWrapper(this.buildCellListener_()); } protected PropertyChangeListener buildCellListener_() { return new PropertyChangeListener() { + @SuppressWarnings("unchecked") public void propertyChanged(PropertyChangeEvent evt) { - TableModelAdapter.this.cellChanged((PropertyValueModel) evt.getSource()); + TableModelAdapter.this.cellChanged((WritablePropertyValueModel<Object>) evt.getSource()); } @Override public String toString() { @@ -168,7 +177,7 @@ public class TableModelAdapter // ********** TableModel implementation ********** public int getColumnCount() { - return this.columnAdapter.getColumnCount(); + return this.columnAdapter.columnCount(); } public int getRowCount() { @@ -177,27 +186,27 @@ public class TableModelAdapter @Override public String getColumnName(int column) { - return this.columnAdapter.getColumnName(column); + return this.columnAdapter.columnName(column); } @Override - public Class getColumnClass(int columnIndex) { - return this.columnAdapter.getColumnClass(columnIndex); + public Class<?> getColumnClass(int columnIndex) { + return this.columnAdapter.columnClass(columnIndex); } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { - return this.columnAdapter.isColumnEditable(columnIndex); + return this.columnAdapter.columnIsEditable(columnIndex); } public Object getValueAt(int rowIndex, int columnIndex) { - PropertyValueModel[] row = this.rows.get(rowIndex); + WritablePropertyValueModel<Object>[] row = this.rows.get(rowIndex); return row[columnIndex].value(); } @Override public void setValueAt(Object value, int rowIndex, int columnIndex) { - PropertyValueModel[] row = this.rows.get(rowIndex); + WritablePropertyValueModel<Object>[] row = this.rows.get(rowIndex); row[columnIndex].setValue(value); } @@ -229,14 +238,14 @@ public class TableModelAdapter /** * Return the underlying list model. */ - public ListValueModel getModel() { + public ListValueModel<? extends E> model() { return this.listHolder; } /** * Set the underlying list model. */ - public void setModel(ListValueModel listHolder) { + public void setModel(ListValueModel<E> listHolder) { if (listHolder == null) { throw new NullPointerException(); } @@ -254,8 +263,8 @@ public class TableModelAdapter /** * Set the underlying collection model. */ - public void setModel(CollectionValueModel collectionHolder) { - this.setModel(new CollectionListValueModelAdapter(collectionHolder)); + public void setModel(CollectionValueModel<E> collectionHolder) { + this.setModel(new CollectionListValueModelAdapter<E>(collectionHolder)); } @@ -292,8 +301,8 @@ public class TableModelAdapter */ private void engageAllCells() { this.rows.ensureCapacity(this.listHolder.size()); - for (Iterator stream = this.listHolder.iterator(); stream.hasNext(); ) { - PropertyValueModel[] row = this.columnAdapter.cellModels(stream.next()); + for (Iterator<? extends E> stream = this.listHolder.iterator(); stream.hasNext(); ) { + WritablePropertyValueModel<Object>[] row = this.columnAdapter.cellModels(stream.next()); this.engageRow(row); this.rows.add(row); } @@ -302,9 +311,9 @@ public class TableModelAdapter /** * Listen to the cells in the specified row. */ - private void engageRow(PropertyValueModel[] row) { + private void engageRow(WritablePropertyValueModel<Object>[] row) { for (int i = row.length; i-- > 0; ) { - row[i].addPropertyChangeListener(ValueModel.VALUE, this.cellListener); + row[i].addPropertyChangeListener(PropertyValueModel.VALUE, this.cellListener); } } @@ -317,24 +326,24 @@ public class TableModelAdapter } private void disengageAllCells() { - for (PropertyValueModel[] row : this.rows) { + for (WritablePropertyValueModel<Object>[] row : this.rows) { this.disengageRow(row); } this.rows.clear(); } - private void disengageRow(PropertyValueModel[] row) { + private void disengageRow(WritablePropertyValueModel<Object>[] row) { for (int i = row.length; i-- > 0; ) { - row[i].removePropertyChangeListener(ValueModel.VALUE, this.cellListener); + row[i].removePropertyChangeListener(PropertyValueModel.VALUE, this.cellListener); } } /** * brute-force search for the cell(s) that changed... */ - void cellChanged(PropertyValueModel cellHolder) { + void cellChanged(WritablePropertyValueModel<Object> cellHolder) { for (int i = this.rows.size(); i-- > 0; ) { - PropertyValueModel[] row = this.rows.get(i); + WritablePropertyValueModel<Object>[] row = this.rows.get(i); for (int j = row.length; j-- > 0; ) { if (row[j] == cellHolder) { this.fireTableCellUpdated(i, j); @@ -346,10 +355,10 @@ public class TableModelAdapter /** * convert the items to rows */ - void addRows(int index, int size, Iterator items) { - List<PropertyValueModel[]> newRows = new ArrayList<PropertyValueModel[]>(size); + void addRows(int index, int size, Iterator<Object> items) { + List<WritablePropertyValueModel<Object>[]> newRows = new ArrayList<WritablePropertyValueModel<Object>[]>(size); while (items.hasNext()) { - PropertyValueModel[] row = this.columnAdapter.cellModels(items.next()); + WritablePropertyValueModel<Object>[] row = this.columnAdapter.cellModels(items.next()); this.engageRow(row); newRows.add(row); } @@ -364,10 +373,10 @@ public class TableModelAdapter this.fireTableRowsDeleted(index, index + size - 1); } - void replaceRows(int index, Iterator items) { + void replaceRows(int index, Iterator<Object> items) { int i = index; while (items.hasNext()) { - PropertyValueModel[] row = this.rows.get(i); + WritablePropertyValueModel<Object>[] row = this.rows.get(i); this.disengageRow(row); row = this.columnAdapter.cellModels(items.next()); this.engageRow(row); @@ -378,7 +387,7 @@ public class TableModelAdapter } void moveRows(int targetIndex, int sourceIndex, int length) { - ArrayList<PropertyValueModel[]> temp = new ArrayList<PropertyValueModel[]>(length); + ArrayList<WritablePropertyValueModel<Object>[]> temp = new ArrayList<WritablePropertyValueModel<Object>[]>(length); for (int i = 0; i < length; i++) { temp.add(this.rows.remove(sourceIndex)); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ToggleButtonModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ToggleButtonModelAdapter.java index 3369513434..0fc40049ea 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ToggleButtonModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ToggleButtonModelAdapter.java @@ -19,8 +19,8 @@ import org.eclipse.jpt.utility.internal.StringTools; import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent; import org.eclipse.jpt.utility.internal.model.listener.PropertyChangeListener; import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper; +import org.eclipse.jpt.utility.internal.model.value.WritablePropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This javax.swing.ButtonModel can be used to keep a listener @@ -37,7 +37,7 @@ public class ToggleButtonModelAdapter protected final boolean defaultValue; /** A value model on the underlying model boolean. */ - protected final PropertyValueModel booleanHolder; + protected final WritablePropertyValueModel<Boolean> booleanHolder; /** * A listener that allows us to synchronize with @@ -51,7 +51,7 @@ public class ToggleButtonModelAdapter /** * Constructor - the boolean holder is required. */ - public ToggleButtonModelAdapter(PropertyValueModel booleanHolder, boolean defaultValue) { + public ToggleButtonModelAdapter(WritablePropertyValueModel<Boolean> booleanHolder, boolean defaultValue) { super(); if (booleanHolder == null) { throw new NullPointerException(); @@ -67,7 +67,7 @@ public class ToggleButtonModelAdapter * Constructor - the boolean holder is required. * The default value will be false. */ - public ToggleButtonModelAdapter(PropertyValueModel booleanHolder) { + public ToggleButtonModelAdapter(WritablePropertyValueModel<Boolean> booleanHolder) { this(booleanHolder, false); } @@ -180,7 +180,7 @@ public class ToggleButtonModelAdapter return this.listenerList.getListenerCount() == 0; } - protected boolean getDefaultValue() { + protected boolean defaultValue() { return this.defaultValue; } @@ -193,7 +193,7 @@ public class ToggleButtonModelAdapter */ protected void setSelected(Boolean value) { if (value == null) { - this.setSelected(this.getDefaultValue()); + this.setSelected(this.defaultValue()); } else { this.setSelected(value.booleanValue()); } @@ -207,12 +207,12 @@ public class ToggleButtonModelAdapter } protected void engageModel() { - this.booleanHolder.addPropertyChangeListener(ValueModel.VALUE, this.booleanChangeListener); - this.setSelected((Boolean) this.booleanHolder.value()); + this.booleanHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener); + this.setSelected(this.booleanHolder.value()); } protected void disengageModel() { - this.booleanHolder.removePropertyChangeListener(ValueModel.VALUE, this.booleanChangeListener); + this.booleanHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TreeModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TreeModelAdapter.java index 1b7d81f490..380286cf31 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TreeModelAdapter.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TreeModelAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -29,9 +29,8 @@ import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeList import org.eclipse.jpt.utility.internal.model.listener.awt.AWTStateChangeListenerWrapper; import org.eclipse.jpt.utility.internal.model.value.ListValueModel; import org.eclipse.jpt.utility.internal.model.value.PropertyValueModel; -import org.eclipse.jpt.utility.internal.model.value.ReadOnlyPropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.StaticPropertyValueModel; import org.eclipse.jpt.utility.internal.model.value.TreeNodeValueModel; -import org.eclipse.jpt.utility.internal.model.value.ValueModel; /** * This javax.swing.tree.TreeModel can be used to keep a TreeModelListener @@ -45,7 +44,7 @@ import org.eclipse.jpt.utility.internal.model.value.ValueModel; * which, typically, should not be a problem. (If you want to display an empty * tree you can set the JTree's treeModel to null.) */ -public class TreeModelAdapter +public class TreeModelAdapter<T> extends AbstractTreeModel { /** @@ -54,7 +53,7 @@ public class TreeModelAdapter * the entire tree. Due to limitations in JTree, the root should * never be set to null while we have listeners. */ - private final PropertyValueModel rootHolder; + private final PropertyValueModel<TreeNodeValueModel<T>> rootHolder; private final PropertyChangeListener rootListener; /** @@ -86,7 +85,7 @@ public class TreeModelAdapter * most of the time. The root is cached so we can disengage * from it when it has been swapped out. */ - private TreeNodeValueModel root; + private TreeNodeValueModel<T> root; /** * Map the nodes to their lists of children. @@ -95,7 +94,7 @@ public class TreeModelAdapter * the items that were affected). * @see EventChangePolicy#rebuildChildren() */ - final IdentityHashMap<TreeNodeValueModel, List<TreeNodeValueModel>> childrenLists; + final IdentityHashMap<TreeNodeValueModel<T>, List<TreeNodeValueModel<T>>> childrenLists; /** * Map the children models to their parents. @@ -103,7 +102,7 @@ public class TreeModelAdapter * list change events (the parent). * @see EventChangePolicy#parent() */ - final IdentityHashMap<ListValueModel, TreeNodeValueModel> parents; + final IdentityHashMap<ListValueModel<TreeNodeValueModel<T>>, TreeNodeValueModel<T>> parents; // ********** constructors ********** @@ -111,7 +110,7 @@ public class TreeModelAdapter /** * Construct a tree model for the specified root. */ - public TreeModelAdapter(PropertyValueModel rootHolder) { + public TreeModelAdapter(PropertyValueModel<TreeNodeValueModel<T>> rootHolder) { super(); if (rootHolder == null) { throw new NullPointerException(); @@ -121,15 +120,15 @@ public class TreeModelAdapter this.nodeStateListener = this.buildNodeStateListener(); this.nodeValueListener = this.buildNodeValueListener(); this.childrenListener = this.buildChildrenListener(); - this.childrenLists = new IdentityHashMap<TreeNodeValueModel, List<TreeNodeValueModel>>(); - this.parents = new IdentityHashMap<ListValueModel, TreeNodeValueModel>(); + this.childrenLists = new IdentityHashMap<TreeNodeValueModel<T>, List<TreeNodeValueModel<T>>>(); + this.parents = new IdentityHashMap<ListValueModel<TreeNodeValueModel<T>>, TreeNodeValueModel<T>>(); } /** * Construct a tree model for the specified root. */ - public TreeModelAdapter(TreeNodeValueModel root) { - this(new ReadOnlyPropertyValueModel(root)); + public TreeModelAdapter(TreeNodeValueModel<T> root) { + this(new StaticPropertyValueModel<TreeNodeValueModel<T>>(root)); } @@ -157,8 +156,9 @@ public class TreeModelAdapter protected PropertyChangeListener buildNodeValueListener_() { return new PropertyChangeListener() { + @SuppressWarnings("unchecked") public void propertyChanged(PropertyChangeEvent e) { - TreeModelAdapter.this.nodeChanged((TreeNodeValueModel) e.getSource()); + TreeModelAdapter.this.nodeChanged((TreeNodeValueModel<T>) e.getSource()); } @Override public String toString() { @@ -173,8 +173,9 @@ public class TreeModelAdapter protected StateChangeListener buildNodeStateListener_() { return new StateChangeListener() { + @SuppressWarnings("unchecked") public void stateChanged(StateChangeEvent e) { - TreeModelAdapter.this.nodeChanged((TreeNodeValueModel) e.getSource()); + TreeModelAdapter.this.nodeChanged((TreeNodeValueModel<T>) e.getSource()); } @Override public String toString() { @@ -221,24 +222,29 @@ public class TreeModelAdapter return this.root; } + @SuppressWarnings("unchecked") public Object getChild(Object parent, int index) { - return ((TreeNodeValueModel) parent).child(index); + return ((TreeNodeValueModel<T>) parent).child(index); } + @SuppressWarnings("unchecked") public int getChildCount(Object parent) { - return ((TreeNodeValueModel) parent).childrenSize(); + return ((TreeNodeValueModel<T>) parent).childrenSize(); } + @SuppressWarnings("unchecked") public boolean isLeaf(Object node) { - return ((TreeNodeValueModel) node).isLeaf(); + return ((TreeNodeValueModel<T>) node).isLeaf(); } + @SuppressWarnings("unchecked") public void valueForPathChanged(TreePath path, Object newValue) { - ((TreeNodeValueModel) path.getLastPathComponent()).setValue(newValue); + ((TreeNodeValueModel<T>) path.getLastPathComponent()).setValue((T) newValue); } + @SuppressWarnings("unchecked") public int getIndexOfChild(Object parent, Object child) { - return ((TreeNodeValueModel) parent).indexOfChild((TreeNodeValueModel) child); + return ((TreeNodeValueModel<T>) parent).indexOfChild((TreeNodeValueModel<T>) child); } /** @@ -271,8 +277,8 @@ public class TreeModelAdapter * in the underlying tree model. */ private void engageModel() { - this.rootHolder.addPropertyChangeListener(ValueModel.VALUE, this.rootListener); - this.root = (TreeNodeValueModel) this.rootHolder.value(); + this.rootHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.rootListener); + this.root = this.rootHolder.value(); if (this.root == null) { throw new NullPointerException(); // the root cannot be null while we have listeners } @@ -295,7 +301,7 @@ public class TreeModelAdapter this.removeRoot(); this.disengageNode(this.root); this.root = null; - this.rootHolder.removePropertyChangeListener(ValueModel.VALUE, this.rootListener); + this.rootHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.rootListener); } /** @@ -312,7 +318,7 @@ public class TreeModelAdapter * non-root nodes. */ void rootChanged() { - TreeNodeValueModel newRoot = (TreeNodeValueModel) this.rootHolder.value(); + TreeNodeValueModel<T> newRoot = this.rootHolder.value(); if (newRoot == null) { throw new NullPointerException(); // the root cannot be null while we have listeners } @@ -321,7 +327,7 @@ public class TreeModelAdapter this.removeRoot(); // save the old root and swap in the new root - TreeNodeValueModel oldRoot = this.root; + TreeNodeValueModel<T> oldRoot = this.root; this.root = newRoot; // we must be listening to both the old and new roots when we fire the event @@ -340,8 +346,8 @@ public class TreeModelAdapter * Either the "value" or the "state" of the specified node has changed, * forward notification to our listeners. */ - void nodeChanged(TreeNodeValueModel node) { - TreeNodeValueModel parent = node.parent(); + void nodeChanged(TreeNodeValueModel<T> node) { + TreeNodeValueModel<T> parent = node.parent(); if (parent == null) { this.fireTreeRootChanged(node); } else { @@ -355,23 +361,23 @@ public class TreeModelAdapter * We must listen to the nodes before notifying anybody, because * adding a listener can change the value of a node. */ - void addChildren(Object[] path, int[] childIndices, Object[] children) { + void addChildren(TreeNodeValueModel<T>[] path, int[] childIndices, TreeNodeValueModel<T>[] children) { int len = childIndices.length; for (int i = 0; i < len; i++) { - this.engageNode((TreeNodeValueModel) children[i]); + this.engageNode(children[i]); } this.fireTreeNodesInserted(path, childIndices, children); for (int i = 0; i < len; i++) { - this.addNode(childIndices[i], (TreeNodeValueModel) children[i]); + this.addNode(childIndices[i], children[i]); } } /** * Listen to the node and its children model. */ - private void engageNode(TreeNodeValueModel node) { + private void engageNode(TreeNodeValueModel<T> node) { node.addStateChangeListener(this.nodeStateListener); - node.addPropertyChangeListener(ValueModel.VALUE, this.nodeValueListener); + node.addPropertyChangeListener(PropertyValueModel.VALUE, this.nodeValueListener); node.childrenModel().addListChangeListener(ListValueModel.LIST_VALUES, this.childrenListener); } @@ -380,7 +386,7 @@ public class TreeModelAdapter * then recurse down through the node's children, * adding them to the internal tree also. */ - private void addNode(int index, TreeNodeValueModel node) { + private void addNode(int index, TreeNodeValueModel<T> node) { this.addNodeToInternalTree(node.parent(), index, node, node.childrenModel()); new NodeChangePolicy(node).addChildren(); } @@ -388,10 +394,10 @@ public class TreeModelAdapter /** * Add the specified node to our internal tree. */ - private void addNodeToInternalTree(TreeNodeValueModel parent, int index, TreeNodeValueModel node, ListValueModel childrenModel) { - List<TreeNodeValueModel> siblings = this.childrenLists.get(parent); + private void addNodeToInternalTree(TreeNodeValueModel<T> parent, int index, TreeNodeValueModel<T> node, ListValueModel<TreeNodeValueModel<T>> childrenModel) { + List<TreeNodeValueModel<T>> siblings = this.childrenLists.get(parent); if (siblings == null) { - siblings = new ArrayList<TreeNodeValueModel>(); + siblings = new ArrayList<TreeNodeValueModel<T>>(); this.childrenLists.put(parent, siblings); } siblings.add(index, node); @@ -405,15 +411,15 @@ public class TreeModelAdapter * We must listen to the nodes until after notifying anybody, because * removing a listener can change the value of a node. */ - void removeChildren(Object[] path, int[] childIndices, Object[] children) { + void removeChildren(TreeNodeValueModel<T>[] path, int[] childIndices, TreeNodeValueModel<T>[] children) { int len = childIndices.length; for (int i = 0; i < len; i++) { // the indices slide down a notch each time we remove a child - this.removeNode(childIndices[i] - i, (TreeNodeValueModel) children[i]); + this.removeNode(childIndices[i] - i, children[i]); } this.fireTreeNodesRemoved(path, childIndices, children); for (int i = 0; i < len; i++) { - this.disengageNode((TreeNodeValueModel) children[i]); + this.disengageNode(children[i]); } } @@ -422,7 +428,7 @@ public class TreeModelAdapter * removing them from our internal tree; * then remove the node itself from our internal tree. */ - private void removeNode(int index, TreeNodeValueModel node) { + private void removeNode(int index, TreeNodeValueModel<T> node) { new NodeChangePolicy(node).removeChildren(); this.removeNodeFromInternalTree(node.parent(), index, node, node.childrenModel()); } @@ -430,10 +436,10 @@ public class TreeModelAdapter /** * Remove the specified node from our internal tree. */ - private void removeNodeFromInternalTree(TreeNodeValueModel parent, int index, TreeNodeValueModel node, ListValueModel childrenModel) { + private void removeNodeFromInternalTree(TreeNodeValueModel<T> parent, int index, TreeNodeValueModel<T> node, ListValueModel<TreeNodeValueModel<T>> childrenModel) { this.parents.remove(childrenModel); - List<TreeNodeValueModel> siblings = this.childrenLists.get(parent); + List<TreeNodeValueModel<T>> siblings = this.childrenLists.get(parent); siblings.remove(index); if (siblings.isEmpty()) { this.childrenLists.remove(parent); @@ -443,15 +449,15 @@ public class TreeModelAdapter /** * Stop listening to the node and its children model. */ - private void disengageNode(TreeNodeValueModel node) { + private void disengageNode(TreeNodeValueModel<T> node) { node.childrenModel().removeListChangeListener(ListValueModel.LIST_VALUES, this.childrenListener); - node.removePropertyChangeListener(ValueModel.VALUE, this.nodeValueListener); + node.removePropertyChangeListener(PropertyValueModel.VALUE, this.nodeValueListener); node.removeStateChangeListener(this.nodeStateListener); } - void moveChildren(TreeNodeValueModel parent, int targetIndex, int sourceIndex, int length) { - List<TreeNodeValueModel> childrenList = this.childrenLists.get(parent); - ArrayList<TreeNodeValueModel> temp = new ArrayList<TreeNodeValueModel>(length); + void moveChildren(TreeNodeValueModel<T> parent, int targetIndex, int sourceIndex, int length) { + List<TreeNodeValueModel<T>> childrenList = this.childrenLists.get(parent); + ArrayList<TreeNodeValueModel<T>> temp = new ArrayList<TreeNodeValueModel<T>>(length); for (int i = 0; i < length; i++) { temp.add(childrenList.remove(sourceIndex)); } @@ -505,7 +511,7 @@ public class TreeModelAdapter /** * Return an array of the current set of children. */ - Object[] childArray() { + TreeNodeValueModel<T>[] childArray() { return this.buildArray(this.children(), this.childrenSize()); } @@ -513,8 +519,9 @@ public class TreeModelAdapter * Build an array to hold the elements in the specified iterator. * If they are different sizes, something is screwed up... */ - Object[] buildArray(Iterator<?> stream, int size) { - Object[] array = new Object[size]; + TreeNodeValueModel<T>[] buildArray(Iterator<TreeNodeValueModel<T>> stream, int size) { + @SuppressWarnings("unchecked") + TreeNodeValueModel<T>[] array = new TreeNodeValueModel[size]; for (int i = 0; stream.hasNext(); i++) { array[i] = stream.next(); } @@ -545,7 +552,7 @@ public class TreeModelAdapter /** * Return the parent of the current set of children. */ - abstract TreeNodeValueModel parent(); + abstract TreeNodeValueModel<T> parent(); /** * Return the starting index for the current set of children. @@ -560,7 +567,7 @@ public class TreeModelAdapter /** * Return an interator on the current set of children. */ - abstract Iterator children(); + abstract Iterator<TreeNodeValueModel<T>> children(); } @@ -580,7 +587,7 @@ public class TreeModelAdapter * Map the ListChangeEvent's source to the corresponding parent. */ @Override - TreeNodeValueModel parent() { + TreeNodeValueModel<T> parent() { return TreeModelAdapter.this.parents.get(this.event.getSource()); } @@ -604,15 +611,16 @@ public class TreeModelAdapter * The ListChangeEvent's items are the children. */ @Override - Iterator children() { - return this.event.items(); + @SuppressWarnings("unchecked") + Iterator<TreeNodeValueModel<T>> children() { + return (Iterator<TreeNodeValueModel<T>>) this.event.items(); } /** * Remove the old nodes and add the new ones. */ void replaceChildren() { - Object[] parentPath = this.parent().path(); + TreeNodeValueModel<T>[] parentPath = this.parent().path(); int[] childIndices = this.childIndices(); TreeModelAdapter.this.removeChildren(parentPath, childIndices, this.replacedChildren()); TreeModelAdapter.this.addChildren(parentPath, childIndices, this.childArray()); @@ -629,11 +637,11 @@ public class TreeModelAdapter * Clear all the nodes. */ void clearChildren() { - TreeNodeValueModel parent = this.parent(); - Object[] parentPath = parent.path(); - List<TreeNodeValueModel> childrenList = TreeModelAdapter.this.childrenLists.get(parent); + TreeNodeValueModel<T> parent = this.parent(); + TreeNodeValueModel<T>[] parentPath = parent.path(); + List<TreeNodeValueModel<T>> childrenList = TreeModelAdapter.this.childrenLists.get(parent); int[] childIndices = this.buildIndices(childrenList.size()); - Object[] childArray = this.buildArray(childrenList.iterator(), childrenList.size()); + TreeNodeValueModel<T>[] childArray = this.buildArray(childrenList.iterator(), childrenList.size()); TreeModelAdapter.this.removeChildren(parentPath, childIndices, childArray); } @@ -641,11 +649,11 @@ public class TreeModelAdapter * Remove all the old nodes and add all the new nodes. */ void rebuildChildren() { - TreeNodeValueModel parent = this.parent(); - Object[] parentPath = parent.path(); - List<TreeNodeValueModel> childrenList = TreeModelAdapter.this.childrenLists.get(parent); + TreeNodeValueModel<T> parent = this.parent(); + TreeNodeValueModel<T>[] parentPath = parent.path(); + List<TreeNodeValueModel<T>> childrenList = TreeModelAdapter.this.childrenLists.get(parent); int[] childIndices = this.buildIndices(childrenList.size()); - Object[] childArray = this.buildArray(childrenList.iterator(), childrenList.size()); + TreeNodeValueModel<T>[] childArray = this.buildArray(childrenList.iterator(), childrenList.size()); TreeModelAdapter.this.removeChildren(parentPath, childIndices, childArray); childIndices = this.buildIndices(parent.childrenModel().size()); @@ -656,8 +664,9 @@ public class TreeModelAdapter /** * The ListChangeEvent's replaced items are the replaced children. */ - Object[] replacedChildren() { - return this.buildArray(this.event.replacedItems(), this.event.itemsSize()); + @SuppressWarnings("unchecked") + TreeNodeValueModel<T>[] replacedChildren() { + return this.buildArray((Iterator<TreeNodeValueModel<T>>) this.event.replacedItems(), this.event.itemsSize()); } } @@ -667,9 +676,9 @@ public class TreeModelAdapter * Wraps a TreeNodeValueModel for adding and removing its children. */ private class NodeChangePolicy extends ChangePolicy { - private TreeNodeValueModel node; + private TreeNodeValueModel<T> node; - NodeChangePolicy(TreeNodeValueModel node) { + NodeChangePolicy(TreeNodeValueModel<T> node) { this.node = node; } @@ -677,7 +686,7 @@ public class TreeModelAdapter * The node itself is the parent. */ @Override - TreeNodeValueModel parent() { + TreeNodeValueModel<T> parent() { return this.node; } @@ -706,7 +715,7 @@ public class TreeModelAdapter * the children model. */ @Override - Iterator children() { + Iterator<TreeNodeValueModel<T>> children() { return this.node.childrenModel().iterator(); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AbstractNode.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AbstractNode.java index 918f3c5ce1..c7709ee3d7 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AbstractNode.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AbstractNode.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -633,10 +633,10 @@ public abstract class AbstractNode * Only really used for testing and debugging. */ public final Iterator<Node> allDirtyNodes() { - return new FilteringIterator<Node>(this.allNodes()) { + return new FilteringIterator<Node, Node>(this.allNodes()) { @Override - protected boolean accept(Object o) { - return (o instanceof AbstractNode) && ((AbstractNode) o).isDirty(); + protected boolean accept(Node node) { + return (node instanceof AbstractNode) && ((AbstractNode) node).isDirty(); } }; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/PluggableValidator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/PluggableValidator.java index d4fa10a441..c44f8aab43 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/PluggableValidator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/PluggableValidator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -21,6 +21,7 @@ public class PluggableValidator implements Node.Validator { private boolean pause; + private boolean validateOnResume; private final Delegate delegate; @@ -44,11 +45,14 @@ public class PluggableValidator public PluggableValidator(Delegate delegate) { super(); this.pause = false; + this.validateOnResume = false; this.delegate = delegate; } public synchronized void validate() { - if ( ! this.pause) { + if (this.pause) { + this.validateOnResume = true; + } else { this.delegate.validate(); } } @@ -65,8 +69,11 @@ public class PluggableValidator throw new IllegalStateException("not paused"); } this.pause = false; - // validate all the changes that occurred while the validation was paused - this.delegate.validate(); + // validate any changes that occurred while the validation was paused + if (this.validateOnResume) { + this.validateOnResume = false; + this.delegate.validate(); + } } @Override @@ -92,9 +99,7 @@ public class PluggableValidator * This delegate does nothing. */ final class Null implements Delegate { - @SuppressWarnings("unchecked") public static final Delegate INSTANCE = new Null(); - @SuppressWarnings("unchecked") public static Delegate instance() { return INSTANCE; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CheckBoxTableCellRenderer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CheckBoxTableCellRenderer.java index 15c2fd0e42..6cbd37ddd2 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CheckBoxTableCellRenderer.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CheckBoxTableCellRenderer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -200,7 +200,7 @@ public class CheckBoxTableCellRenderer implements TableCellEditorAdapter.Rendere * to set the table's row height to something the check box * will look good in.... */ - public int getPreferredHeight() { + public int preferredHeight() { // add in space for the border top and bottom return (int) this.checkBox.getPreferredSize().getHeight() + 2; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ComboBoxTableCellRenderer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ComboBoxTableCellRenderer.java index ba2a1581a0..d0db82bbdf 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ComboBoxTableCellRenderer.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ComboBoxTableCellRenderer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -178,7 +178,7 @@ public class ComboBoxTableCellRenderer implements TableCellEditorAdapter.Rendere private JList getListBox(JComboBox result) { - return (JList) ClassTools.getFieldValue(result.getUI(), "listBox"); + return (JList) ClassTools.fieldValue(result.getUI(), "listBox"); } @@ -323,7 +323,7 @@ public class ComboBoxTableCellRenderer implements TableCellEditorAdapter.Rendere * Return the renderer's preferred height. This allows you * to set the row height to something the combo-box will look good in.... */ - public int getPreferredHeight() { + public int preferredHeight() { return height; } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListBrowser.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListBrowser.java index e5a1d39523..d59f3e04d3 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListBrowser.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListBrowser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -20,10 +20,10 @@ import javax.swing.ListModel; * is passed a FilteringListPanel to assist the user in making * a selection. */ -public class FilteringListBrowser +public class FilteringListBrowser<T> implements ListChooser.ListBrowser { - private FilteringListPanel panel; + private FilteringListPanel<T> panel; /** * Default constructor. @@ -33,8 +33,8 @@ public class FilteringListBrowser this.panel = this.buildPanel(); } - protected FilteringListPanel buildPanel() { - return new LocalFilteringListPanel(); + protected FilteringListPanel<T> buildPanel() { + return new LocalFilteringListPanel<T>(); } /** @@ -57,16 +57,16 @@ public class FilteringListBrowser ); if (option == JOptionPane.OK_OPTION) { - chooser.getModel().setSelectedItem(this.panel.getSelection()); + chooser.getModel().setSelectedItem(this.panel.selection()); } // clear the text field so the list box is re-filtered - this.panel.getTextField().setText(""); + this.panel.textField().setText(""); } protected void initializeCellRenderer(JComboBox comboBox) { // default behavior should be to use the cell renderer from the combobox. - this.panel.getListBox().setCellRenderer(comboBox.getRenderer()); + this.panel.listBox().setCellRenderer(comboBox.getRenderer()); } /** @@ -118,10 +118,11 @@ public class FilteringListBrowser // ********** custom panel ********** - protected class LocalFilteringListPanel extends FilteringListPanel { - + protected static class LocalFilteringListPanel<S> extends FilteringListPanel<S> { + protected static final Object[] EMPTY_ARRAY = new Object[0]; + protected LocalFilteringListPanel() { - super(new Object[0], null); + super(EMPTY_ARRAY, null); } /** @@ -129,9 +130,11 @@ public class FilteringListBrowser * will try open wide enough to disable the horizontal scroll bar; * and it looks a bit clumsy. */ + @Override protected String prototypeCellValue() { return null; } } + } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListPanel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListPanel.java index bb36dfbef5..af9a56dac8 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListPanel.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListPanel.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -65,7 +65,7 @@ import org.eclipse.jpt.utility.internal.StringMatcher; * dialog that directs the user's behavior (as opposed to a "normal" * window). */ -public class FilteringListPanel extends JPanel { +public class FilteringListPanel<T> extends JPanel { /** * The complete list of available choices @@ -78,7 +78,7 @@ public class FilteringListPanel extends JPanel { * to strings so they can be run through the matcher * and displayed in the text field. */ - StringConverter stringConverter; + StringConverter<T> stringConverter; /** The text field. */ private JTextField textField; @@ -120,7 +120,7 @@ public class FilteringListPanel extends JPanel { * the objects). */ public FilteringListPanel(Object[] completeList, Object initialSelection) { - this(completeList, initialSelection, StringConverter.Default.instance()); + this(completeList, initialSelection, StringConverter.Default.<T>instance()); } /** @@ -128,7 +128,7 @@ public class FilteringListPanel extends JPanel { * and initial selection. Use the specified string converter to convert the * choices and selection to strings. */ - public FilteringListPanel(Object[] completeList, Object initialSelection, StringConverter stringConverter) { + public FilteringListPanel(Object[] completeList, Object initialSelection, StringConverter<T> stringConverter) { super(new BorderLayout()); this.completeList = completeList; this.stringConverter = stringConverter; @@ -140,7 +140,7 @@ public class FilteringListPanel extends JPanel { private void initialize(Object initialSelection) { this.maxListSize = this.defaultMaxListSize(); - this.buffer = new Object[this.max()]; + this.buffer = this.buildBuffer(); this.textFieldListener = this.buildTextFieldListener(); @@ -149,6 +149,10 @@ public class FilteringListPanel extends JPanel { this.initializeLayout(initialSelection); } + private Object[] buildBuffer() { + return new Object[this.max()]; + } + /** * Return the current max number of entries allowed in the list box. */ @@ -186,7 +190,7 @@ public class FilteringListPanel extends JPanel { } private StringMatcher buildStringMatcher() { - return new SimpleStringMatcher(); + return new SimpleStringMatcher<T>(); } private void initializeLayout(Object initialSelection) { @@ -234,7 +238,7 @@ public class FilteringListPanel extends JPanel { // ********** public API ********** - public Object getSelection() { + public Object selection() { return this.listBox.getSelectedValue(); } @@ -242,7 +246,7 @@ public class FilteringListPanel extends JPanel { this.listBox.setSelectedValue(selection, true); } - public Object[] getCompleteList() { + public Object[] completeList() { return this.completeList; } @@ -253,33 +257,33 @@ public class FilteringListPanel extends JPanel { public void setCompleteList(Object[] completeList) { this.completeList = completeList; if (this.buffer.length < this.max()) { - // the buffer will never shrink - might want to re-consider... -bjv - this.buffer = new Object[this.max()]; + // the buffer will never shrink - might want to re-consider... ~bjv + this.buffer = this.buildBuffer(); } this.filterList(); } - public int getMaxListSize() { + public int maxListSize() { return this.maxListSize; } public void setMaxListSize(int maxListSize) { this.maxListSize = maxListSize; if (this.buffer.length < this.max()) { - // the buffer will never shrink - might want to re-consider... -bjv - this.buffer = new Object[this.max()]; + // the buffer will never shrink - might want to re-consider... ~bjv + this.buffer = this.buildBuffer(); } this.filterList(); } - public StringConverter getStringConverter() { + public StringConverter<T> stringConverter() { return this.stringConverter; } /** * apply the new filter to the list */ - public void setStringConverter(StringConverter stringConverter) { + public void setStringConverter(StringConverter<T> stringConverter) { this.stringConverter = stringConverter; this.filterList(); } @@ -288,14 +292,14 @@ public class FilteringListPanel extends JPanel { * allow client code to access the text field * (so we can set the focus) */ - public JTextField getTextField() { + public JTextField textField() { return this.textField; } /** * allow client code to access the text field label */ - public JLabel getTextFieldLabel() { + public JLabel textFieldLabel() { return this.textFieldLabel; } @@ -310,7 +314,7 @@ public class FilteringListPanel extends JPanel { * allow client code to access the list box * (so we can add mouse listeners for double-clicking) */ - public JList getListBox() { + public JList listBox() { return this.listBox; } @@ -324,7 +328,7 @@ public class FilteringListPanel extends JPanel { /** * allow client code to access the list box label */ - public JLabel getListBoxLabel() { + public JLabel listBoxLabel() { return this.listBoxLabel; } @@ -345,7 +349,7 @@ public class FilteringListPanel extends JPanel { this.listBox.setFont(font); } - public StringMatcher getStringMatcher() { + public StringMatcher stringMatcher() { return this.stringMatcher; } @@ -375,8 +379,9 @@ public class FilteringListPanel extends JPanel { protected ListCellRenderer buildDefaultCellRenderer() { return new SimpleListCellRenderer() { @Override + @SuppressWarnings("unchecked") protected String buildText(Object value) { - return FilteringListPanel.this.stringConverter.convertToString(value); + return FilteringListPanel.this.stringConverter.convertToString((T) value); } }; } @@ -385,7 +390,7 @@ public class FilteringListPanel extends JPanel { * Something has changed that requires us to filter the list. * * This method is synchronized because a fast typist can - * generate events quicker than we can filter the list. (? -bjv) + * generate events quicker than we can filter the list. (? ~bjv) */ synchronized void filterList() { // temporarily stop listening to the list box selection, since we will @@ -407,7 +412,7 @@ public class FilteringListPanel extends JPanel { int len = this.completeList.length; int max = this.max(); for (int i = 0; i < len; i++) { - if (this.stringMatcher.matches(this.stringConverter.convertToString(this.completeList[i]))) { + if (this.stringMatcher.matches(this.stringConverter.convertToString(this.entry(i)))) { this.buffer[j++] = this.completeList[i]; } if (j == max) { @@ -428,6 +433,14 @@ public class FilteringListPanel extends JPanel { } /** + * minimize scope of suppressed warnings + */ + @SuppressWarnings("unchecked") + private T entry(int index) { + return (T) this.completeList[index]; + } + + /** * Build a list model that wraps only a portion of the specified array. * The model will include the array entries from 0 to (size - 1). */ diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ListChooser.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ListChooser.java index 52f8c8f9a4..2ddca8b367 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ListChooser.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ListChooser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -113,12 +113,12 @@ public class ListChooser //These are used to workaround problems with Swing trying to //determine the size of a comboBox with a large model setPrototypeDisplayValue(prototypeLabel); - getListBox().setPrototypeCellValue(prototypeLabel); + listBox().setPrototypeCellValue(prototypeLabel); } - private JList getListBox() { - return (JList) ClassTools.getFieldValue(this.ui, "listBox"); + private JList listBox() { + return (JList) ClassTools.fieldValue(this.ui, "listBox"); } /** @@ -215,7 +215,7 @@ public class ListChooser private void updateArrowButton() { try { BasicComboBoxUI comboBoxUi = (BasicComboBoxUI) ListChooser.this.getUI(); - JButton arrowButton = (JButton) ClassTools.getFieldValue(comboBoxUi, "arrowButton"); + JButton arrowButton = (JButton) ClassTools.fieldValue(comboBoxUi, "arrowButton"); arrowButton.setEnabled(this.isEnabled() && this.choosable); } catch (Exception e) { @@ -241,7 +241,7 @@ public class ListChooser // **************** Public ************************************************ - public int getLongListSize() { + public int longListSize() { return this.longListSize; } @@ -389,7 +389,7 @@ public class ListChooser private void checkComboBoxButton() { try { BasicComboBoxUI comboBoxUi = (BasicComboBoxUI) ListChooser.this.getUI(); - JButton arrowButton = (JButton) ClassTools.getFieldValue(comboBoxUi, "arrowButton"); + JButton arrowButton = (JButton) ClassTools.fieldValue(comboBoxUi, "arrowButton"); arrowButton.getModel().setPressed(false); } catch (Exception e) { diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SpinnerTableCellRenderer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SpinnerTableCellRenderer.java index 2f1f07e949..ad071e4ac9 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SpinnerTableCellRenderer.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SpinnerTableCellRenderer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Oracle. All rights reserved. + * Copyright (c) 2007, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -179,7 +179,7 @@ public class SpinnerTableCellRenderer implements TableCellEditorAdapter.Renderer * Return the renderer's preferred height. This allows you * to set the row height to something the spinner will look good in.... */ - public int getPreferredHeight() { + public int preferredHeight() { // add in space for the border top and bottom return (int) this.spinner.getPreferredSize().getHeight() + 2; } |