Losen up restriction so the Utility classes can access forbidden classes, such as Swing classes
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/META-INF/MANIFEST.MF b/tools/org.eclipse.persistence.tools.utility.tests/META-INF/MANIFEST.MF
index 6823e2a..8e995f3 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/META-INF/MANIFEST.MF
+++ b/tools/org.eclipse.persistence.tools.utility.tests/META-INF/MANIFEST.MF
@@ -12,8 +12,10 @@
org.eclipse.persistence.tools.utility.tests.model.listener,
org.eclipse.persistence.tools.utility.tests.model.value,
org.eclipse.persistence.tools.utility.tests.model.value.prefs,
+ org.eclipse.persistence.tools.utility.tests.model.value.swing,
org.eclipse.persistence.tools.utility.tests.node,
org.eclipse.persistence.tools.utility.tests.reference,
+ org.eclipse.persistence.tools.utility.tests.swing,
org.eclipse.persistence.tools.utility.tests.transformer
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.eclipse.persistence.tools.utility;bundle-version="2.5.0",
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/pom.xml b/tools/org.eclipse.persistence.tools.utility.tests/pom.xml
index 3eb6520..c161060 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/pom.xml
+++ b/tools/org.eclipse.persistence.tools.utility.tests/pom.xml
@@ -16,4 +16,18 @@
<relativePath>../org.eclipse.persistence.tools.parent/pom.xml</relativePath>
</parent>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>tycho-compiler-plugin</artifactId>
+ <version>${tycho.version}</version>
+ <configuration>
+ <!-- Remove the restriction to access restricted classes, such as Swing classes. -->
+ <compilerArgument>-err:-forbidden</compilerArgument>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
</project>
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/CommonUtilityTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/CommonUtilityTests.java
index 8ec386b..e973368 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/CommonUtilityTests.java
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/CommonUtilityTests.java
@@ -81,8 +81,8 @@
suite.addTestSuite(SystemToolsTests.class);
suite.addTestSuite(TypeDeclarationToolsTests.class);
suite.addTestSuite(VersionComparatorTests.class);
-// suite.addTestSuite(XMLToolsReadTests.class);
-// suite.addTestSuite(XMLToolsWriteTests.class);
+ suite.addTestSuite(XMLToolsReadTests.class);
+ suite.addTestSuite(XMLToolsWriteTests.class);
return suite;
}
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsReadTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsReadTests.java
new file mode 100644
index 0000000..fb6f19a
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsReadTests.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests;
+
+import java.io.StringReader;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.XMLTools;
+import org.eclipse.persistence.tools.utility.iterable.IterableTools;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+@SuppressWarnings("nls")
+public class XMLToolsReadTests
+ extends TestCase
+{
+ private Document testDocument;
+ private Node rootNode;
+
+
+ public XMLToolsReadTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.testDocument = this.buildTestDocument();
+ this.rootNode = XMLTools.getChild(this.testDocument, "root-element");
+ }
+
+ private Document buildTestDocument() {
+ return XMLTools.parse(new StringReader(this.buildTestDocumentString()));
+ }
+
+ private String buildTestDocumentString() {
+ StringBuffer sb = new StringBuffer(2000);
+ sb.append("<?xml version = '1.0' encoding = 'UTF-8'?>");
+ sb.append("<root-element>");
+ sb.append( "<element-0>");
+ sb.append( "<element-0-text-1>some text</element-0-text-1>");
+ sb.append( "<element-0-text-2></element-0-text-2>");
+ sb.append( "<element-0-text-3/>");
+ sb.append( "<element-0-non-text>");
+ sb.append( "<element-0-non-text-child>");
+ sb.append( "</element-0-non-text-child>");
+ sb.append( "</element-0-non-text>");
+ sb.append( "</element-0>");
+ sb.append( "<element-1>");
+ sb.append( "<element-1-int>42</element-1-int>");
+ sb.append( "<element-1-boolean-true-1>true</element-1-boolean-true-1>");
+ sb.append( "<element-1-boolean-true-2>T</element-1-boolean-true-2>");
+ sb.append( "<element-1-boolean-true-3>1</element-1-boolean-true-3>");
+ sb.append( "<element-1-boolean-false-1>false</element-1-boolean-false-1>");
+ sb.append( "<element-1-boolean-false-2>F</element-1-boolean-false-2>");
+ sb.append( "<element-1-boolean-false-3>0</element-1-boolean-false-3>");
+ sb.append( "</element-1>");
+ sb.append( "<element-2>");
+ sb.append( "<element-2.0>");
+ sb.append( "</element-2.0>");
+ sb.append( "<element-2.0>");
+ sb.append( "</element-2.0>");
+ sb.append( "<element-2.0>");
+ sb.append( "</element-2.0>");
+ sb.append( "</element-2>");
+ sb.append( "<element-3>element 3 contents</element-3>");
+ sb.append("</root-element>");
+ return sb.toString();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testGetChild() {
+ assertEquals("element-1", XMLTools.getChild(this.rootNode, "element-1").getNodeName());
+ assertEquals("element-3", XMLTools.getChild(this.rootNode, "element-3").getNodeName());
+ assertEquals(null, XMLTools.getChild(this.rootNode, "element-1x"));
+ }
+
+ public void testGetChildren() {
+ Iterable<Node> children = XMLTools.getChildren(this.rootNode);
+ assertEquals(4, IterableTools.size(children));
+ for (int i = 1; i < 4; i++) {
+ assertEquals("element-" + i, IterableTools.get(children, i).getNodeName());
+ }
+ }
+
+ public void testGetChildrenNamed() {
+ Node element2Node = XMLTools.getChild(this.rootNode, "element-2");
+ Iterable<Node> children = XMLTools.getChildren(element2Node, "element-2.0");
+ assertEquals(3, IterableTools.size(children));
+ for (int i = 0; i < 3; i++) {
+ assertEquals("element-2.0", IterableTools.get(children, i).getNodeName());
+ }
+ }
+
+ public void testGetTextContent() {
+ Node node = XMLTools.getChild(this.rootNode, "element-0");
+ Node childNode = XMLTools.getChild(node, "element-0-text-1");
+ assertEquals("some text", XMLTools.getTextContent(childNode));
+
+ childNode = XMLTools.getChild(node, "element-0-text-2");
+ assertEquals("", XMLTools.getTextContent(childNode));
+
+ childNode = XMLTools.getChild(node, "element-0-text-3");
+ assertEquals("", XMLTools.getTextContent(childNode));
+
+ childNode = XMLTools.getChild(node, "element-0-non-text");
+ boolean exCaught = false;
+ try {
+ String text = XMLTools.getTextContent(childNode);
+ text = text.toString();
+ } catch (IllegalArgumentException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testGetChildTextContent() {
+ assertEquals("element 3 contents", XMLTools.getChildTextContent(this.rootNode, "element-3"));
+ }
+
+ public void testGetChildTextContentDefaultValue() {
+ assertEquals("element 3 contents", XMLTools.getChildTextContent(this.rootNode, "element-3", "default value 3"));
+ assertEquals("default value 4", XMLTools.getChildTextContent(this.rootNode, "element-4", "default value 4"));
+ }
+
+ public void testGetChildIntContent() {
+ Node node = XMLTools.getChild(this.rootNode, "element-1");
+ assertEquals(42, XMLTools.getChildIntContent(node, "element-1-int"));
+ }
+
+ public void testGetChildIntContentDefaultValue() {
+ Node node = XMLTools.getChild(this.rootNode, "element-1");
+ assertEquals(42, XMLTools.childIntContent(node, "element-1-int", 99));
+ assertEquals(99, XMLTools.childIntContent(node, "element-1-int-x", 99));
+ }
+
+ public void testGetChildBooleanContent() {
+ Node node = XMLTools.getChild(this.rootNode, "element-1");
+ assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-1"));
+ assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-2"));
+ assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-3"));
+
+ assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-1"));
+ assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-2"));
+ assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-3"));
+ }
+
+ public void testGetChildBooleanContentDefaultValue() {
+ Node node = XMLTools.getChild(this.rootNode, "element-1");
+ assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-1", false));
+ assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-2", false));
+ assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-3", false));
+ assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-bogus", false));
+
+ assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-1", true));
+ assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-2", true));
+ assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-3", true));
+ assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-bogus", true));
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsWriteTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsWriteTests.java
new file mode 100644
index 0000000..46b3a5f
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsWriteTests.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.StringTools;
+import org.eclipse.persistence.tools.utility.SystemTools;
+import org.eclipse.persistence.tools.utility.XMLTools;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * these tests assume the XML will be formatted with appropriate
+ * indentation?
+ */
+@SuppressWarnings("nls")
+public class XMLToolsWriteTests
+ extends TestCase
+{
+ private Document testDocument;
+ private Node rootNode;
+ private static final String CR = System.getProperty("line.separator");
+
+
+ public XMLToolsWriteTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.testDocument = XMLTools.newDocument();
+ this.rootNode = this.testDocument.createElement("root-element");
+ this.testDocument.appendChild(this.rootNode);
+ XMLTools.addSimpleTextNode(this.rootNode, "element-0", "foo");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ private void verifyTestDocumentString(String string) throws Exception {
+ OutputStream stream = new ByteArrayOutputStream(2000);
+ XMLTools.print(this.testDocument, stream);
+ stream.close();
+ StringBuffer sb = new StringBuffer(2000);
+ sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"");
+ if (SystemTools.jvmIsOracle() && SystemTools.javaSpecificationVersionIsGreaterThan("1.5")) {
+ sb.append(" standalone=\"no\"");
+ }
+ sb.append("?>");
+ if (SystemTools.jvmIsOracle() || (SystemTools.jvmIsIBM() && SystemTools.javaSpecificationVersionIsLessThanOrEqualTo("1.5"))) {
+ sb.append(CR);
+ }
+ sb.append("<root-element>");
+ sb.append(CR);
+ sb.append("<element-0>");
+ sb.append("foo");
+ sb.append("</element-0>");
+ sb.append(CR);
+ sb.append(string);
+ sb.append("</root-element>");
+ if (SystemTools.jvmIsOracle() || (SystemTools.jvmIsIBM() && SystemTools.javaSpecificationVersionIsLessThanOrEqualTo("1.5"))) {
+ sb.append(CR);
+ }
+ String expected = sb.toString();
+ String actual = stream.toString();
+ assertEquals(StringTools.compressWhitespace(expected), StringTools.compressWhitespace(actual));
+ }
+
+ public void testAddSimpleTextNode() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", "some text");
+ this.verifyTestDocumentString("<element-1>some text</element-1>" + CR);
+ }
+
+ public void testAddSimpleTextNodeDefaultValue1() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", "some text", "some text");
+ this.verifyTestDocumentString("");
+ }
+
+ public void testAddSimpleTextNodeDefaultValue2() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", "some text", "default text");
+ this.verifyTestDocumentString("<element-1>some text</element-1>" + CR);
+ }
+
+ public void testAddSimpleTextNodeInt() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", 42);
+ this.verifyTestDocumentString("<element-1>42</element-1>" + CR);
+ }
+
+ public void testAddSimpleTextNodeIntDefaultValue1() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", 42, 42);
+ this.verifyTestDocumentString("");
+ }
+
+ public void testAddSimpleTextNodeIntDefaultValue2() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", 42, 43);
+ this.verifyTestDocumentString("<element-1>42</element-1>" + CR);
+ }
+
+ public void testAddSimpleTextNodeBoolean() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", true);
+ this.verifyTestDocumentString("<element-1>true</element-1>" + CR);
+ }
+
+ public void testAddSimpleTextNodeBooleanDefaultValue1() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", true, true);
+ this.verifyTestDocumentString("");
+ }
+
+ public void testAddSimpleTextNodeBooleanDefaultValue2() throws Exception {
+ XMLTools.addSimpleTextNode(this.rootNode, "element-1", false, true);
+ this.verifyTestDocumentString("<element-1>false</element-1>" + CR);
+ }
+
+ public void testAddSimpleTextNodes() throws Exception {
+ XMLTools.addSimpleTextNodes(this.rootNode, "element-1-collection", "element-1", new String[] {"text 1", "text 2", "text 3"});
+ StringBuffer sb = new StringBuffer(2000);
+ sb.append("<element-1-collection>");
+ sb.append(CR);
+ sb.append("<element-1>text 1</element-1>");
+ sb.append(CR);
+ sb.append("<element-1>text 2</element-1>");
+ sb.append(CR);
+ sb.append("<element-1>text 3</element-1>");
+ sb.append(CR);
+ sb.append("</element-1-collection>");
+ sb.append(CR);
+ this.verifyTestDocumentString(sb.toString());
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/Displayable.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/Displayable.java
new file mode 100644
index 0000000..d990942
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/Displayable.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model;
+
+import javax.swing.Icon;
+import org.eclipse.persistence.tools.utility.model.Model;
+
+/**
+ * Used by general-purpose UI models and renderers to cast
+ * application model objects to something displayable.
+ */
+@SuppressWarnings("nls")
+public interface Displayable
+ extends Model
+{
+ /**
+ * Return a string that can be used to identify the model
+ * in a textual UI setting (typically the object's name).
+ * When the display string changes, the model should fire
+ * the appropriate change notification:<pre>
+ * this.firePropertyChanged(DISPLAY_STRING_PROPERTY, oldDisplayString, this.displayString);
+ * </pre>
+ */
+ String displayString();
+ String DISPLAY_STRING_PROPERTY = "displayString";
+
+ /**
+ * Return an icon that can be used to identify the model
+ * in a UI component that supports icons (the icon can be null).
+ * When the icon changes, the model should fire
+ * the appropriate change notification:<pre>
+ * this.firePropertyChanged(ICON_PROPERTY, oldIcon, this.icon);
+ * </pre>
+ */
+ Icon icon();
+ String ICON_PROPERTY = "icon";
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/SimpleDisplayable.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/SimpleDisplayable.java
new file mode 100644
index 0000000..6efa650
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/SimpleDisplayable.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model;
+
+import javax.swing.Icon;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+
+/**
+ * This implementation of {@link Displayable} converts any {@link Object}
+ * to a {@link Displayable}. Subclass it to override {@link #displayString()} and
+ * {@link #icon()} if necessary. Change notification will be fired if the
+ * object is changed.
+ * <p>
+ * This can be used for {@link String}s - the display string
+ * will simply be the string itself.
+ */
+public class SimpleDisplayable
+ extends AbstractModel
+ implements Displayable
+{
+ /** The object to be converted to a displayable. */
+ protected Object object;
+
+
+ /**
+ * Construct a displayable for the specified object.
+ */
+ public SimpleDisplayable(Object object) {
+ super();
+ this.object = object;
+ }
+
+ public SimpleDisplayable(boolean b) {
+ this(Boolean.valueOf(b));
+ }
+
+ public SimpleDisplayable(char c) {
+ this(Character.valueOf(c));
+ }
+
+ public SimpleDisplayable(byte b) {
+ this(Byte.valueOf(b));
+ }
+
+ public SimpleDisplayable(short s) {
+ this(Short.valueOf(s));
+ }
+
+ public SimpleDisplayable(int i) {
+ this(Integer.valueOf(i));
+ }
+
+ public SimpleDisplayable(long l) {
+ this(Long.valueOf(l));
+ }
+
+ public SimpleDisplayable(float f) {
+ this(Float.valueOf(f));
+ }
+
+ public SimpleDisplayable(double d) {
+ this(Double.valueOf(d));
+ }
+
+
+ // ********** Displayable implementation **********
+
+ @Override
+ public String displayString() {
+ return this.object.toString();
+ }
+
+ @Override
+ public Icon icon() {
+ return null;
+ }
+
+
+ // ********** accessors **********
+
+ public Object getObject() {
+ return this.object;
+ }
+
+ public void setObject(Object object) {
+ String oldDisplayString = this.displayString();
+ Icon oldIcon = this.icon();
+ this.object = object;
+ this.firePropertyChanged(DISPLAY_STRING_PROPERTY, oldDisplayString, this.displayString());
+ this.firePropertyChanged(ICON_PROPERTY, oldIcon, this.icon());
+ }
+
+ public boolean getBoolean() {
+ return ((Boolean) this.object).booleanValue();
+ }
+
+ public void setBoolean(boolean b) {
+ this.setObject(Boolean.valueOf(b));
+ }
+
+ public char getChar() {
+ return ((Character) this.object).charValue();
+ }
+
+ public void setChar(char c) {
+ this.setObject(Character.valueOf(c));
+ }
+
+ public byte getByte() {
+ return ((Byte) this.object).byteValue();
+ }
+
+ public void setByte(byte b) {
+ this.setObject(Byte.valueOf(b));
+ }
+
+ public short getShort() {
+ return ((Short) this.object).shortValue();
+ }
+
+ public void setShort(short s) {
+ this.setObject(Short.valueOf(s));
+ }
+
+ public int getInt() {
+ return ((Integer) this.object).intValue();
+ }
+
+ public void setInt(int i) {
+ this.setObject(Integer.valueOf(i));
+ }
+
+ public long getLong() {
+ return ((Long) this.object).longValue();
+ }
+
+ public void setLong(long l) {
+ this.setObject(Long.valueOf(l));
+ }
+
+ public float getFloat() {
+ return ((Float) this.object).floatValue();
+ }
+
+ public void setFloat(float f) {
+ this.setObject(Float.valueOf(f));
+ }
+
+ public double getDouble() {
+ return ((Double) this.object).doubleValue();
+ }
+
+ public void setDouble(double d) {
+ this.setObject(Double.valueOf(d));
+ }
+
+
+ // ********** override methods **********
+
+ @Override
+ public void toString(StringBuilder sb) {
+ sb.append(this.object);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CollectionListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CollectionListValueModelAdapterTests.java
new file mode 100644
index 0000000..0c5e1d9
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CollectionListValueModelAdapterTests.java
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.Collection;
+import java.util.List;
+import javax.swing.JList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CollectionListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class CollectionListValueModelAdapterTests extends TestCase {
+ private ListValueModel<String> adapter;
+ private SimpleCollectionValueModel<String> wrappedCollectionHolder;
+ private Collection<String> wrappedCollection;
+
+ public CollectionListValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.wrappedCollection = new HashBag<String>();
+ this.wrappedCollectionHolder = new SimpleCollectionValueModel<String>(this.wrappedCollection);
+ this.adapter = new CollectionListValueModelAdapter<String>(this.wrappedCollectionHolder);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testIterator() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ });
+ this.wrappedCollectionHolder.add("foo");
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ Collection<String> adapterCollection = this.adapterCollection();
+ assertEquals(3, adapterCollection.size());
+ assertEquals(this.wrappedCollection, adapterCollection);
+ }
+
+ private Collection<String> adapterCollection() {
+ return CollectionTools.collection(this.adapter.iterator());
+ }
+
+ public void testStaleValue() {
+ ListChangeListener listener = new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ };
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ this.wrappedCollectionHolder.add("foo");
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ Collection<String> adapterCollection = this.adapterCollection();
+ assertEquals(3, adapterCollection.size());
+ assertEquals(this.wrappedCollection, adapterCollection);
+
+ this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, listener);
+ adapterCollection = this.adapterCollection();
+ assertEquals(0, adapterCollection.size());
+ assertEquals(new HashBag<String>(), adapterCollection);
+
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ adapterCollection = this.adapterCollection();
+ assertEquals(3, adapterCollection.size());
+ assertEquals(this.wrappedCollection, adapterCollection);
+ }
+
+ public void testAdd() {
+ List<String> synchList = new CoordinatedList<String>(this.adapter);
+ Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+ this.wrappedCollectionHolder.add("foo");
+ assertTrue(this.wrappedCollection.contains("foo"));
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ this.wrappedCollectionHolder.add("joo");
+ this.wrappedCollectionHolder.add("jar");
+ this.wrappedCollectionHolder.add("jaz");
+ assertEquals(6, this.wrappedCollection.size());
+
+ Collection<String> adapterCollection = this.adapterCollection();
+ assertEquals(this.wrappedCollection, adapterCollection);
+ assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+ assertEquals(this.wrappedCollection, synchCollection);
+ }
+
+ public void testRemove() {
+ List<String> synchList = new CoordinatedList<String>(this.adapter);
+ Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+ this.wrappedCollectionHolder.add("foo");
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ this.wrappedCollectionHolder.add("joo");
+ this.wrappedCollectionHolder.add("jar");
+ this.wrappedCollectionHolder.add("jaz");
+ assertTrue(this.wrappedCollection.contains("jaz"));
+ this.wrappedCollectionHolder.remove("jaz");
+ assertFalse(this.wrappedCollection.contains("jaz"));
+ this.wrappedCollectionHolder.remove("foo");
+ assertFalse(this.wrappedCollection.contains("foo"));
+ assertEquals(4, this.wrappedCollection.size());
+
+ Collection<String> adapterCollection = this.adapterCollection();
+ assertEquals(this.wrappedCollection, adapterCollection);
+ assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+ assertEquals(this.wrappedCollection, synchCollection);
+ }
+
+ public void testListSynch() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+ });
+ this.wrappedCollectionHolder.add("foo");
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ this.wrappedCollectionHolder.add("joo");
+ this.wrappedCollectionHolder.add("jar");
+ this.wrappedCollectionHolder.add("jaz");
+ this.wrappedCollectionHolder.remove("jaz");
+ assertFalse(this.wrappedCollection.contains("jaz"));
+ this.wrappedCollectionHolder.remove("foo");
+ assertFalse(this.wrappedCollection.contains("foo"));
+ assertEquals(4, this.wrappedCollection.size());
+
+ Collection<String> adapterCollection = this.adapterCollection();
+ assertEquals(this.wrappedCollection, adapterCollection);
+ }
+
+ public void testHasListeners() {
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ CoordinatedList<String> synchList = new CoordinatedList<String>(this.adapter);
+ assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ ChangeListener cl = new ChangeAdapter();
+ this.adapter.addChangeListener(cl);
+ assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.adapter.removeChangeListener(cl);
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ public void testCollectionChangedToEmpty() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void listCleared(ListClearEvent e) {/* OK */}
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ });
+ this.wrappedCollectionHolder.add("foo");
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+ this.wrappedCollectionHolder.setValues(new HashBag<String>());
+ assertEquals(0, jList.getModel().getSize());
+ }
+
+ public void testCollectionChangedFromEmpty() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+ });
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+
+ HashBag<String> bag = new HashBag<String>();
+ bag.add("foo");
+ bag.add("bar");
+ this.wrappedCollectionHolder.setValues(bag);
+ assertEquals(2, jList.getModel().getSize());
+ }
+
+ public void testCollectionChangedFromEmptyToEmpty() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+ });
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+
+ HashBag<String> bag = new HashBag<String>();
+ this.wrappedCollectionHolder.setValues(bag);
+ assertEquals(0, jList.getModel().getSize());
+ }
+
+
+ class TestListChangeListener implements ListChangeListener {
+ @Override
+ public void itemsAdded(ListAddEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsMoved(ListMoveEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void listCleared(ListClearEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void listChanged(ListChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CompositeListValueModelTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CompositeListValueModelTests.java
new file mode 100644
index 0000000..05a5dab
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CompositeListValueModelTests.java
@@ -0,0 +1,1256 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CompositeListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class CompositeListValueModelTests extends TestCase {
+
+ private LocalListValueModel<String> lvm0;
+ private LocalListValueModel<String> lvm1;
+ private LocalListValueModel<String> lvm2;
+ private LocalListValueModel<String> lvm3;
+ private LocalListValueModel<LocalListValueModel<String>> uberLVM;
+ private CompositeListValueModel<LocalListValueModel<String>, String> compositeLVM;
+
+ public CompositeListValueModelTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.lvm0 = new LocalListValueModel<String>();
+ this.lvm0.add("aaa");
+ this.lvm0.add("bbb");
+ this.lvm0.add("ccc");
+
+ this.lvm1 = new LocalListValueModel<String>();
+ this.lvm1.add("ddd");
+ this.lvm1.add("eee");
+
+ this.lvm2 = new LocalListValueModel<String>();
+ this.lvm2.add("fff");
+
+ this.lvm3 = new LocalListValueModel<String>();
+ this.lvm3.add("ggg");
+ this.lvm3.add("hhh");
+ this.lvm3.add("iii");
+ this.lvm3.add("jjj");
+ this.lvm3.add("kkk");
+
+ this.uberLVM = new LocalListValueModel<LocalListValueModel<String>>();
+ this.uberLVM.add(this.lvm0);
+ this.uberLVM.add(this.lvm1);
+ this.uberLVM.add(this.lvm2);
+ this.uberLVM.add(this.lvm3);
+
+ this.compositeLVM = CompositeListValueModel.forModels((ListValueModel<LocalListValueModel<String>>) this.uberLVM);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testGetInt() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+ assertEquals("aaa", this.compositeLVM.get(0));
+ assertEquals("aaa", coordList.get(0));
+ assertEquals("bbb", this.compositeLVM.get(1));
+ assertEquals("bbb", coordList.get(1));
+ assertEquals("ccc", this.compositeLVM.get(2));
+ assertEquals("ccc", coordList.get(2));
+
+ assertEquals("ddd", this.compositeLVM.get(3));
+ assertEquals("ddd", coordList.get(3));
+ assertEquals("eee", this.compositeLVM.get(4));
+ assertEquals("eee", coordList.get(4));
+
+ assertEquals("fff", this.compositeLVM.get(5));
+ assertEquals("fff", coordList.get(5));
+
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testIterator() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+ assertEquals("aaa", this.compositeLVM.iterator().next());
+ assertEquals("aaa", coordList.iterator().next());
+ Iterator<String> stream1 = coordList.iterator();
+ for (Iterator<String> stream2 = this.compositeLVM.iterator(); stream2.hasNext(); ) {
+ assertEquals(stream1.next(), stream2.next());
+ }
+ assertFalse(stream1.hasNext());
+ }
+
+ public void testSize() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+ assertEquals(11, this.compositeLVM.size());
+ assertEquals(11, coordList.size());
+ }
+
+ public void testToArray() {
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ }
+
+ public void testHasListeners() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ assertTrue(this.compositeLVM.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(this.lvm0.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ this.compositeLVM.removeListChangeListener(ListValueModel.LIST_VALUES, coordList);
+ assertFalse(this.compositeLVM.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.lvm0.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, coordList);
+ assertTrue(this.compositeLVM.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(this.lvm0.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ public void testAddSource_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ LocalListValueModel<String> lvm = new LocalListValueModel<String>();
+ lvm.add("xxx");
+ lvm.add("yyy");
+ lvm.add("zzz");
+ this.uberLVM.add(0, lvm);
+
+ Object[] expected = new Object[] { "xxx", "yyy", "zzz", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(9));
+ assertEquals("ggg", coordList.get(9));
+ }
+
+ public void testAddSource_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ LocalListValueModel<String> lvm = new LocalListValueModel<String>();
+ lvm.add("xxx");
+ lvm.add("yyy");
+ lvm.add("zzz");
+ this.uberLVM.add(2, lvm);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "yyy", "zzz", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(9));
+ assertEquals("ggg", coordList.get(9));
+ }
+
+ public void testAddSource_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ LocalListValueModel<String> lvm = new LocalListValueModel<String>();
+ lvm.add("xxx");
+ lvm.add("yyy");
+ lvm.add("zzz");
+ this.uberLVM.add(lvm);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "xxx", "yyy", "zzz" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testAddSources() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ LocalListValueModel<String> lvmA = new LocalListValueModel<String>();
+ lvmA.add("xxx");
+ lvmA.add("yyy");
+ lvmA.add("zzz");
+ LocalListValueModel<String> lvmB = new LocalListValueModel<String>();
+ lvmB.add("ppp");
+ lvmB.add("qqq");
+ lvmB.add("rrr");
+ Collection<LocalListValueModel<String>> c = new ArrayList<LocalListValueModel<String>>();
+ c.add(lvmA);
+ c.add(lvmB);
+ this.uberLVM.addAll(2, c);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "yyy", "zzz", "ppp", "qqq", "rrr", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(12));
+ assertEquals("ggg", coordList.get(12));
+ }
+
+ public void testRemoveSource_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.remove(0);
+
+ Object[] expected = new Object[] { "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(3));
+ assertEquals("ggg", coordList.get(3));
+ }
+
+ public void testRemoveSource_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.remove(2);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(5));
+ assertEquals("ggg", coordList.get(5));
+ }
+
+ public void testRemoveSource_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.remove(3);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("fff", this.compositeLVM.get(5));
+ assertEquals("fff", coordList.get(5));
+ }
+
+ public void testRemoveSources() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.remove(2, 2);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("eee", this.compositeLVM.get(4));
+ assertEquals("eee", coordList.get(4));
+ }
+
+ public void testReplaceSources() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ LocalListValueModel<String> lvmA = new LocalListValueModel<String>();
+ lvmA.add("xxx");
+ lvmA.add("yyy");
+ lvmA.add("zzz");
+ LocalListValueModel<String> lvmB = new LocalListValueModel<String>();
+ lvmB.add("ppp");
+ lvmB.add("qqq");
+ lvmB.add("rrr");
+ List<LocalListValueModel<String>> list = new ArrayList<LocalListValueModel<String>>();
+ list.add(lvmA);
+ list.add(lvmB);
+ this.uberLVM.set(2, list);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "yyy", "zzz", "ppp", "qqq", "rrr" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("qqq", this.compositeLVM.get(9));
+ assertEquals("qqq", coordList.get(9));
+ }
+
+ public void testMoveSources_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.move(0, 2, 2);
+
+ Object[] expected = new Object[] { "fff", "ggg", "hhh", "iii", "jjj", "kkk", "aaa", "bbb", "ccc", "ddd", "eee" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(1));
+ assertEquals("ggg", coordList.get(1));
+ }
+
+ public void testMoveSources_Middle() {
+ LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+ lvm4.add("lll");
+ lvm4.add("mmm");
+ this.uberLVM.add(lvm4);
+
+ LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+ lvm5.add("nnn");
+ lvm5.add("ooo");
+ lvm5.add("ppp");
+ lvm5.add("qqq");
+ this.uberLVM.add(lvm5);
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.move(1, 3, 2);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "ddd", "eee", "fff", "nnn", "ooo", "ppp", "qqq" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(3));
+ assertEquals("ggg", coordList.get(3));
+ }
+
+ public void testMoveSources_End() {
+ LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+ lvm4.add("lll");
+ lvm4.add("mmm");
+ this.uberLVM.add(lvm4);
+
+ LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+ lvm5.add("nnn");
+ lvm5.add("ooo");
+ lvm5.add("ppp");
+ lvm5.add("qqq");
+ this.uberLVM.add(lvm5);
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.move(3, 0, 3);
+
+ Object[] expected = new Object[] { "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(0));
+ assertEquals("ggg", coordList.get(0));
+ }
+
+ public void testMoveSource() {
+ LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+ lvm4.add("lll");
+ lvm4.add("mmm");
+ this.uberLVM.add(lvm4);
+
+ LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+ lvm5.add("nnn");
+ lvm5.add("ooo");
+ lvm5.add("ppp");
+ lvm5.add("qqq");
+ this.uberLVM.add(lvm5);
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.move(3, 1);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "ddd", "eee", "lll", "mmm", "nnn", "ooo", "ppp", "qqq" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ooo", this.compositeLVM.get(14));
+ assertEquals("ooo", coordList.get(14));
+ }
+
+ public void testClearSources() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.clear();
+
+ Object[] expected = new Object[0];
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ }
+
+ public void testChangeSources1() {
+ List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+ LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+ lvm4.add("lll");
+ lvm4.add("mmm");
+ newList.add(lvm4);
+
+ LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+ lvm5.add("nnn");
+ lvm5.add("ooo");
+ lvm5.add("ppp");
+ lvm5.add("qqq");
+ newList.add(lvm5);
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.setListValues(newList);
+
+ Object[] expected = new Object[] { "lll", "mmm", "nnn", "ooo", "ppp", "qqq" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ooo", this.compositeLVM.get(3));
+ assertEquals("ooo", coordList.get(3));
+ }
+
+ public void testChangeSources2() {
+ List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+ LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+ lvm4.add("lll");
+ lvm4.add("mmm");
+ newList.add(lvm4);
+
+ LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+ lvm5.add("nnn");
+ lvm5.add("ooo");
+ lvm5.add("ppp");
+ lvm5.add("qqq");
+ newList.add(lvm5);
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.changeListValues(newList);
+
+ Object[] expected = new Object[] { "lll", "mmm", "nnn", "ooo", "ppp", "qqq" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ooo", this.compositeLVM.get(3));
+ assertEquals("ooo", coordList.get(3));
+ }
+
+ public void testChangeSources3() {
+ ListChangeListener listener = new ErrorListener();
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+
+ List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+ newList.add(this.lvm0);
+ newList.add(this.lvm1);
+ newList.add(this.lvm2);
+ newList.add(this.lvm3);
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.changeListValues(newList);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ddd", this.compositeLVM.get(3));
+ assertEquals("ddd", coordList.get(3));
+ }
+
+ public void testChangeSources4() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+
+ List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+ newList.add(this.lvm0);
+ newList.add(this.lvm1);
+ newList.add(this.lvm2);
+ newList.add(this.lvm3);
+ LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+ lvm4.add("lll");
+ lvm4.add("mmm");
+ newList.add(lvm4);
+
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.changeListValues(newList);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ddd", this.compositeLVM.get(3));
+ assertEquals("ddd", coordList.get(3));
+ }
+
+ public void testChangeSources5() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+
+ List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+ newList.add(this.lvm0);
+ newList.add(this.lvm1);
+ newList.add(this.lvm2);
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.changeListValues(newList);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ddd", this.compositeLVM.get(3));
+ assertEquals("ddd", coordList.get(3));
+ }
+
+ public void testChangeSources6() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) { /* OK */ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+
+ List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+ newList.add(this.lvm0);
+ newList.add(this.lvm1);
+
+ LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+ lvm4.add("lll");
+ lvm4.add("mmm");
+ newList.add(lvm4);
+
+ newList.add(this.lvm3);
+
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.uberLVM.changeListValues(newList);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "lll", "mmm", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ddd", this.compositeLVM.get(3));
+ assertEquals("ddd", coordList.get(3));
+ }
+
+ public void testAddItem_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.add(0, "xxx");
+
+ Object[] expected = new Object[] { "xxx", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(7));
+ assertEquals("ggg", coordList.get(7));
+ }
+
+ public void testAddItem_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm2.add(1, "xxx");
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "xxx", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(7));
+ assertEquals("ggg", coordList.get(7));
+ }
+
+ public void testAddItem_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.add(5, "xxx");
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "xxx" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testAddItems_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.addAll(0, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+ Object[] expected = new Object[] { "xxx", "yyy", "zzz", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(9));
+ assertEquals("ggg", coordList.get(9));
+ }
+
+ public void testAddItems_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm2.addAll(1, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "xxx", "yyy", "zzz", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(9));
+ assertEquals("ggg", coordList.get(9));
+ }
+
+ public void testAddItems_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.addAll(5, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "xxx", "yyy", "zzz" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testRemoveItem_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.remove(0);
+
+ Object[] expected = new Object[] { "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(5));
+ assertEquals("ggg", coordList.get(5));
+ }
+
+ public void testRemoveItem_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm2.remove(0);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(5));
+ assertEquals("ggg", coordList.get(5));
+ }
+
+ public void testRemoveItem_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.remove(4);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testRemoveItems_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.remove(0, 3);
+
+ Object[] expected = new Object[] { "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(3));
+ assertEquals("ggg", coordList.get(3));
+ }
+
+ public void testRemoveItems_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.remove(1, 3);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("kkk", this.compositeLVM.get(7));
+ assertEquals("kkk", coordList.get(7));
+ }
+
+ public void testRemoveItems_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.remove(3, 2);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testReplaceItem_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.set(0, "xxx");
+
+ Object[] expected = new Object[] { "xxx", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testReplaceItem_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm2.set(0, "xxx");
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testReplaceItem_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.set(4, "xxx");
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "xxx" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testReplaceItems_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.set(0, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+ Object[] expected = new Object[] { "xxx", "yyy", "zzz", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testReplaceItems_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.set(1, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "xxx", "yyy", "zzz", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("kkk", this.compositeLVM.get(10));
+ assertEquals("kkk", coordList.get(10));
+ }
+
+ public void testReplaceItems_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.set(3, Arrays.asList(new String[] { "xxx", "yyy" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "xxx", "yyy" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testMoveItem_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.move(2, 0);
+
+ Object[] expected = new Object[] { "bbb", "ccc", "aaa", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testMoveItem_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm1.move(0, 1);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "eee", "ddd", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testMoveItem_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.move(0, 4);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "kkk", "ggg", "hhh", "iii", "jjj" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(7));
+ assertEquals("ggg", coordList.get(7));
+ }
+
+ public void testMoveItems_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.move(1, 0, 2);
+
+ Object[] expected = new Object[] { "ccc", "aaa", "bbb", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testMoveItems_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm1.add("eee.1");
+ this.lvm1.add("eee.2");
+ this.lvm1.add("eee.3");
+ this.lvm1.move(1, 2, 3);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee.1", "eee.2", "eee.3", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(9));
+ assertEquals("ggg", coordList.get(9));
+ }
+
+ public void testMoveItems_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.move(0, 2, 3);
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "iii", "jjj", "kkk", "ggg", "hhh" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(9));
+ assertEquals("ggg", coordList.get(9));
+ }
+
+ public void testClearItems_Begin() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.clear();
+
+ Object[] expected = new Object[] { "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(3));
+ assertEquals("ggg", coordList.get(3));
+ }
+
+ public void testClearItems_Middle() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm1.clear();
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(4));
+ assertEquals("ggg", coordList.get(4));
+ }
+
+ public void testClearItems_End() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.clear();
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("fff", this.compositeLVM.get(5));
+ assertEquals("fff", coordList.get(5));
+ }
+
+ public void testChangeItems_Begin1() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.setListValues(Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+ Object[] expected = new Object[] { "xxx", "yyy", "zzz", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testChangeItems_Middle1() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm1.setListValues(Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "xxx", "yyy", "zzz", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(7));
+ assertEquals("ggg", coordList.get(7));
+ }
+
+ public void testChangeItems_End1() {
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.setListValues(Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "xxx", "yyy", "zzz" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("fff", this.compositeLVM.get(5));
+ assertEquals("fff", coordList.get(5));
+ }
+
+ public void testChangeItems_Begin2() {
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, new ErrorListener());
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.changeListValues(Arrays.asList(new String[] { "aaa", "bbb", "ccc" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testChangeItems_Middle2() {
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, new ErrorListener());
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm1.changeListValues(Arrays.asList(new String[] { "ddd", "eee" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("hhh", this.compositeLVM.get(7));
+ assertEquals("hhh", coordList.get(7));
+ }
+
+ public void testChangeItems_End2() {
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, new ErrorListener());
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.changeListValues(Arrays.asList(new String[] { "ggg", "hhh", "iii", "jjj", "kkk" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("fff", this.compositeLVM.get(5));
+ assertEquals("fff", coordList.get(5));
+ }
+
+ public void testChangeItems_Begin3() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.changeListValues(Arrays.asList(new String[] { "aaa", "bbb", "xxx" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "xxx", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(6));
+ assertEquals("ggg", coordList.get(6));
+ }
+
+ public void testChangeItems_Middle3() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm1.changeListValues(Arrays.asList(new String[] { "ddd", "xxx" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "xxx", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("hhh", this.compositeLVM.get(7));
+ assertEquals("hhh", coordList.get(7));
+ }
+
+ public void testChangeItems_End3() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.changeListValues(Arrays.asList(new String[] { "ggg", "hhh", "iii", "xxx", "kkk" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "xxx", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("fff", this.compositeLVM.get(5));
+ assertEquals("fff", coordList.get(5));
+ }
+
+ public void testChangeItems_Begin4() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.changeListValues(Arrays.asList(new String[] { "aaa", "bbb", "ccc", "xxx" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "xxx", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("fff", this.compositeLVM.get(6));
+ assertEquals("fff", coordList.get(6));
+ }
+
+ public void testChangeItems_Middle4() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm1.changeListValues(Arrays.asList(new String[] { "ddd", "eee", "xxx" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("ggg", this.compositeLVM.get(7));
+ assertEquals("ggg", coordList.get(7));
+ }
+
+ public void testChangeItems_End4() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.changeListValues(Arrays.asList(new String[] { "ggg", "hhh", "iii", "jjj", "kkk", "xxx" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "xxx" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("fff", this.compositeLVM.get(5));
+ assertEquals("fff", coordList.get(5));
+ }
+
+ public void testChangeItems_Begin5() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm0.changeListValues(Arrays.asList(new String[] { "aaa" }));
+
+ Object[] expected = new Object[] { "aaa", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("iii", this.compositeLVM.get(6));
+ assertEquals("iii", coordList.get(6));
+ }
+
+ public void testChangeItems_Middle5() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm1.changeListValues(Arrays.asList(new String[] { "ddd" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("iii", this.compositeLVM.get(7));
+ assertEquals("iii", coordList.get(7));
+ }
+
+ public void testChangeItems_End5() {
+ ListChangeListener listener = new ErrorListener() {
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+ };
+ this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+ this.lvm3.changeListValues(Arrays.asList(new String[] { "ggg", "hhh", "iii" }));
+
+ Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii" };
+ assertEquals(expected.length, this.compositeLVM.size());
+ assertEquals(expected.length, coordList.size());
+ assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+ assertTrue(Arrays.equals(expected, coordList.toArray()));
+ assertEquals("fff", this.compositeLVM.get(5));
+ assertEquals("fff", coordList.get(5));
+ }
+
+ class ErrorListener implements ListChangeListener {
+ @Override
+ public void itemsAdded(ListAddEvent event) {
+ fail();
+ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {
+ fail();
+ }
+ @Override
+ public void itemsMoved(ListMoveEvent event) {
+ fail();
+ }
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {
+ fail();
+ }
+ @Override
+ public void listCleared(ListClearEvent event) {
+ fail();
+ }
+ @Override
+ public void listChanged(ListChangeEvent event) {
+ fail();
+ }
+ }
+
+ class LocalListValueModel<E> extends SimpleListValueModel<E> {
+ LocalListValueModel() {
+ super();
+ }
+ void changeListValues(Iterable<E> listValues) {
+ if (listValues == null) {
+ throw new NullPointerException();
+ }
+ this.list.clear();
+ CollectionTools.addAll(this.list, listValues);
+ this.fireListChanged(LIST_VALUES, this.list);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CoordinatedList.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CoordinatedList.java
new file mode 100644
index 0000000..85b5670
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CoordinatedList.java
@@ -0,0 +1,298 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import javax.swing.ListModel;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+
+/**
+ * Helper class that keeps an internal list in synch with the
+ * list held by a list value model.
+ */
+public class CoordinatedList<E> implements List<E>, ListChangeListener, ListDataListener {
+ private List<E> list = new ArrayList<E>();
+
+ public CoordinatedList(ListValueModel<E> listValueModel) {
+ listValueModel.addListChangeListener(ListValueModel.LIST_VALUES, this);
+ for (Iterator<E> stream = listValueModel.iterator(); stream.hasNext(); ) {
+ this.add(stream.next());
+ }
+ }
+
+ public CoordinatedList(ListModel listModel) {
+ listModel.addListDataListener(this);
+ for (int i = 0; i < listModel.getSize(); i++) {
+ this.add(i, this.getElementAt(listModel, i));
+ }
+ }
+
+
+ // ********** List implementation **********
+
+ @Override
+ public void add(int index, E element) {
+ this.list.add(index, element);
+ }
+
+ @Override
+ public boolean add(E o) {
+ return this.list.add(o);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends E> c) {
+ return this.list.addAll(c);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends E> c) {
+ return this.list.addAll(index, c);
+ }
+
+ @Override
+ public void clear() {
+ this.list.clear();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return this.list.contains(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return this.list.containsAll(c);
+ }
+
+ @Override
+ public E get(int index) {
+ return this.list.get(index);
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return this.list.indexOf(o);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.list.isEmpty();
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return this.list.iterator();
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return this.list.lastIndexOf(o);
+ }
+
+ @Override
+ public ListIterator<E> listIterator() {
+ return this.list.listIterator();
+ }
+
+ @Override
+ public ListIterator<E> listIterator(int index) {
+ return this.list.listIterator(index);
+ }
+
+ @Override
+ public E remove(int index) {
+ return this.list.remove(index);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return this.list.remove(o);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ return this.list.removeAll(c);
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ return this.list.retainAll(c);
+ }
+
+ @Override
+ public E set(int index, E element) {
+ return this.list.set(index, element);
+ }
+
+ @Override
+ public int size() {
+ return this.list.size();
+ }
+
+ @Override
+ public List<E> subList(int fromIndex, int toIndex) {
+ return this.list.subList(fromIndex, toIndex);
+ }
+
+ @Override
+ public Object[] toArray() {
+ return this.list.toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return this.list.toArray(a);
+ }
+
+
+ // ********** ListChangeListener implementation **********
+
+ @Override
+ public void itemsAdded(ListAddEvent e) {
+ int i = e.getIndex();
+ for (E item : this.getItems(e)) {
+ this.list.add(i++, item);
+ }
+ }
+
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {
+ int base = e.getIndex();
+ for (int i = e.getItemsSize(); i-- > 0; ) {
+ this.list.remove(base + i); // remove from end
+ }
+ }
+
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {
+ int i = e.getIndex();
+ for (E item : this.getNewItems(e)) {
+ this.list.set(i++, item);
+ }
+ }
+
+ @Override
+ public void itemsMoved(ListMoveEvent e) {
+ ListTools.move(this.list, e.getTargetIndex(), e.getSourceIndex(), e.getLength());
+ }
+
+ @Override
+ public void listCleared(ListClearEvent e) {
+ this.list.clear();
+ }
+
+ @Override
+ public void listChanged(ListChangeEvent e) {
+ this.list.clear();
+ CollectionTools.addAll(this.list, this.getSource(e).iterator());
+ }
+
+
+ // ********** ListDataListener implementation **********
+
+ @Override
+ public void contentsChanged(ListDataEvent e) {
+ this.list.clear();
+ ListModel lm = (ListModel) e.getSource();
+ int size = lm.getSize();
+ for (int i = 0; i < size; i++) {
+ this.list.add(i, this.getElementAt(lm, i));
+ }
+ }
+
+ @Override
+ public void intervalAdded(ListDataEvent e) {
+ ListModel lm = (ListModel) e.getSource();
+ int start = Math.min(e.getIndex0(), e.getIndex1());
+ int end = Math.max(e.getIndex0(), e.getIndex1());
+ for (int i = start; i <= end; i++) {
+ this.list.add(i, this.getElementAt(lm, i));
+ }
+ }
+
+ @Override
+ public void intervalRemoved(ListDataEvent e) {
+ int start = Math.min(e.getIndex0(), e.getIndex1());
+ int end = Math.max(e.getIndex0(), e.getIndex1());
+ int length = end - start + 1;
+ for (int i = 1; i <= length; i++) {
+ this.list.remove(start);
+ }
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public boolean equals(Object o) {
+ return this.list.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.list.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return this.list.toString();
+ }
+
+
+ // ********** internal methods **********
+
+ /**
+ * minimize the scope of the suppressed warnings.=
+ */
+ @SuppressWarnings("unchecked")
+ private E getElementAt(ListModel listModel, int index) {
+ return (E) listModel.getElementAt(index);
+ }
+
+ // minimized scope of suppressed warnings
+ @SuppressWarnings("unchecked")
+ private Iterable<E> getItems(ListAddEvent event) {
+ return (Iterable<E>) event.getItems();
+ }
+
+ // minimized scope of suppressed warnings
+ @SuppressWarnings("unchecked")
+ private Iterable<E> getNewItems(ListReplaceEvent event) {
+ return (Iterable<E>) event.getNewItems();
+ }
+
+ /**
+ * minimize the scope of the suppressed warnings.=
+ */
+ @SuppressWarnings("unchecked")
+ private ListValueModel<E> getSource(ListChangeEvent event) {
+ return (ListValueModel<E>) event.getSource();
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemCollectionListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemCollectionListValueModelAdapterTests.java
new file mode 100644
index 0000000..85fa4cd
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemCollectionListValueModelAdapterTests.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.Icon;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemCollectionListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+@SuppressWarnings("nls")
+public class ItemCollectionListValueModelAdapterTests extends TestCase {
+
+ private Junk foo;
+ private Junk bar;
+ private Junk baz;
+ private Junk joo;
+ private Junk jar;
+ private Junk jaz;
+
+ private Junk tom;
+ private Junk dick;
+ private Junk harry;
+
+ public ItemCollectionListValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.foo = new Junk("foo");
+ this.bar = new Junk("bar");
+ this.baz = new Junk("baz");
+ this.joo = new Junk("joo");
+ this.jar = new Junk("jar");
+ this.jaz = new Junk("jaz");
+
+ this.tom = new Junk("tom");
+ this.dick = new Junk("dick");
+ this.harry = new Junk("harry");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testCollectionSynchronization() {
+ SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+ ListValueModel<Junk> listValueModel = new ItemCollectionListValueModelAdapter<Junk>(collectionHolder, Junk.STUFF_COLLECTION);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.add(this.tom);
+ collectionHolder.add(this.dick);
+ collectionHolder.add(this.harry);
+ assertEquals(9, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.remove(this.foo);
+ collectionHolder.remove(this.jar);
+ collectionHolder.remove(this.harry);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+ }
+
+ public void testListSynchronization() {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemCollectionListValueModelAdapter<Junk>(listHolder, Junk.STUFF_COLLECTION);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ listHolder.add(6, this.tom);
+ listHolder.add(7, this.dick);
+ listHolder.add(8, this.harry);
+ assertEquals(9, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ listHolder.remove(8);
+ listHolder.remove(0);
+ listHolder.remove(4);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+ }
+
+ private void compare(ListValueModel<Junk> listValueModel, List<Junk> list) {
+ assertEquals(listValueModel.size(), list.size());
+ for (int i = 0; i < listValueModel.size(); i++) {
+ assertEquals(listValueModel.get(i), list.get(i));
+ }
+ }
+
+
+ public void testHasListeners() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyListChangeListeners(Junk.STUFF_COLLECTION));
+ assertFalse(this.jaz.hasAnyListChangeListeners(Junk.STUFF_COLLECTION));
+
+ ListValueModel<Junk> listValueModel = new ItemCollectionListValueModelAdapter<Junk>(listHolder, Junk.STUFF_COLLECTION);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+ assertFalse(this.jaz.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+ this.verifyHasNoListeners(listValueModel);
+
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(this.foo.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+ assertTrue(this.jaz.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+ this.verifyHasListeners(listValueModel);
+
+ listValueModel.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+ assertFalse(this.jaz.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+ this.verifyHasNoListeners(listValueModel);
+ }
+
+ public void testGetSize() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemCollectionListValueModelAdapter<Junk>(listHolder, Junk.STUFF_COLLECTION);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ this.verifyHasListeners(listValueModel);
+ assertEquals(6, listValueModel.size());
+ assertEquals(6, synchList.size());
+ }
+
+ public void testGet() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new SortedListValueModelWrapper<Junk>(new ItemCollectionListValueModelAdapter<Junk>(listHolder, Junk.STUFF_COLLECTION));
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ this.verifyHasListeners(listValueModel);
+ assertEquals(this.bar, listValueModel.get(0));
+ assertEquals(this.bar, synchList.get(0));
+ this.bar.removeStuff("bar");
+ this.bar.addStuff("zzz");
+ this.bar.addStuff("bar");
+ assertEquals(this.bar, listValueModel.get(5));
+ assertEquals(this.bar, synchList.get(5));
+ this.bar.removeStuff("zzz");
+ }
+
+ private void verifyHasNoListeners(ListValueModel<Junk> listValueModel) throws Exception {
+ assertTrue(((AbstractModel) listValueModel).hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private void verifyHasListeners(ListValueModel<Junk> listValueModel) throws Exception {
+ assertTrue(((AbstractModel) listValueModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private SimpleCollectionValueModel<Junk> buildCollectionHolder() {
+ return new SimpleCollectionValueModel<Junk>(this.buildCollection());
+ }
+
+ private Collection<Junk> buildCollection() {
+ Bag<Junk> bag = new HashBag<Junk>();
+ this.populateCollection(bag);
+ return bag;
+ }
+
+ private SimpleListValueModel<Junk> buildListHolder() {
+ return new SimpleListValueModel<Junk>(this.buildList());
+ }
+
+ private List<Junk> buildList() {
+ List<Junk> list = new ArrayList<Junk>();
+ this.populateCollection(list);
+ return list;
+ }
+
+ private void populateCollection(Collection<Junk> c) {
+ c.add(this.foo);
+ c.add(this.bar);
+ c.add(this.baz);
+ c.add(this.joo);
+ c.add(this.jar);
+ c.add(this.jaz);
+ }
+
+
+ // ********** Junk class **********
+
+ private class Junk extends AbstractModel implements Displayable, Comparable<Junk> {
+ private Collection<String> stuff;
+ public static final String STUFF_COLLECTION = "stuff";
+
+
+ public Junk(String stuffItem) {
+ this.stuff = new ArrayList<String>();
+ this.stuff.add(stuffItem);
+ }
+
+ public void addStuff(String stuffItem) {
+ this.addItemToCollection(stuffItem, this.stuff, STUFF_COLLECTION);
+ }
+
+ public void removeStuff(String stuffItem) {
+ this.removeItemFromCollection(stuffItem, this.stuff, STUFF_COLLECTION);
+ }
+
+ @Override
+ public String displayString() {
+ return toString();
+ }
+
+ @Override
+ public Icon icon() {
+ return null;
+ }
+
+ @Override
+ public int compareTo(Junk o) {
+ return this.displayString().compareTo(o.displayString());
+ }
+
+ @Override
+ public String toString() {
+ return "Junk(" + this.stuff + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemListListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemListListValueModelAdapterTests.java
new file mode 100644
index 0000000..8006fe0
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemListListValueModelAdapterTests.java
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.Icon;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemListListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+@SuppressWarnings("nls")
+public class ItemListListValueModelAdapterTests extends TestCase {
+
+ private Junk foo;
+ private Junk bar;
+ private Junk baz;
+ private Junk joo;
+ private Junk jar;
+ private Junk jaz;
+
+ private Junk tom;
+ private Junk dick;
+ private Junk harry;
+
+ public ItemListListValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.foo = new Junk("foo");
+ this.bar = new Junk("bar");
+ this.baz = new Junk("baz");
+ this.joo = new Junk("joo");
+ this.jar = new Junk("jar");
+ this.jaz = new Junk("jaz");
+
+ this.tom = new Junk("tom");
+ this.dick = new Junk("dick");
+ this.harry = new Junk("harry");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testCollectionSynchronization() {
+ SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+ ListValueModel<Junk> listValueModel = new ItemListListValueModelAdapter<Junk>(collectionHolder, Junk.STUFF_LIST);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.add(this.tom);
+ collectionHolder.add(this.dick);
+ collectionHolder.add(this.harry);
+ assertEquals(9, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.remove(this.foo);
+ collectionHolder.remove(this.jar);
+ collectionHolder.remove(this.harry);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+ }
+
+ public void testListSynchronization() {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemListListValueModelAdapter<Junk>(listHolder, Junk.STUFF_LIST);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ listHolder.add(6, this.tom);
+ listHolder.add(7, this.dick);
+ listHolder.add(8, this.harry);
+ assertEquals(9, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ listHolder.remove(8);
+ listHolder.remove(0);
+ listHolder.remove(4);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+ }
+
+ private void compare(ListValueModel<Junk> listValueModel, List<Junk> list) {
+ assertEquals(listValueModel.size(), list.size());
+ for (int i = 0; i < listValueModel.size(); i++) {
+ assertEquals(listValueModel.get(i), list.get(i));
+ }
+ }
+
+
+ public void testHasListeners() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyListChangeListeners(Junk.STUFF_LIST));
+ assertFalse(this.jaz.hasAnyListChangeListeners(Junk.STUFF_LIST));
+
+ ListValueModel<Junk> listValueModel = new ItemListListValueModelAdapter<Junk>(listHolder, Junk.STUFF_LIST);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyListChangeListeners(Junk.STUFF_LIST));
+ assertFalse(this.jaz.hasAnyListChangeListeners(Junk.STUFF_LIST));
+ this.verifyHasNoListeners(listValueModel);
+
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(this.foo.hasAnyListChangeListeners(Junk.STUFF_LIST));
+ assertTrue(this.jaz.hasAnyListChangeListeners(Junk.STUFF_LIST));
+ this.verifyHasListeners(listValueModel);
+
+ listValueModel.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyListChangeListeners(Junk.STUFF_LIST));
+ assertFalse(this.jaz.hasAnyListChangeListeners(Junk.STUFF_LIST));
+ this.verifyHasNoListeners(listValueModel);
+ }
+
+ public void testGetSize() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemListListValueModelAdapter<Junk>(listHolder, Junk.STUFF_LIST);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ this.verifyHasListeners(listValueModel);
+ assertEquals(6, listValueModel.size());
+ assertEquals(6, synchList.size());
+ }
+
+ public void testGet() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new SortedListValueModelWrapper<Junk>(new ItemListListValueModelAdapter<Junk>(listHolder, Junk.STUFF_LIST));
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ this.verifyHasListeners(listValueModel);
+ assertEquals(this.bar, listValueModel.get(0));
+ assertEquals(this.bar, synchList.get(0));
+ this.bar.removeStuff("bar");
+ this.bar.addStuff("zzz");
+ this.bar.addStuff("bar");
+ assertEquals(this.bar, listValueModel.get(5));
+ assertEquals(this.bar, synchList.get(5));
+ this.bar.removeStuff("zzz");
+ }
+
+ private void verifyHasNoListeners(ListValueModel<Junk> listValueModel) throws Exception {
+ assertTrue(((AbstractModel) listValueModel).hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private void verifyHasListeners(ListValueModel<Junk> listValueModel) throws Exception {
+ assertTrue(((AbstractModel) listValueModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private SimpleCollectionValueModel<Junk> buildCollectionHolder() {
+ return new SimpleCollectionValueModel<Junk>(this.buildCollection());
+ }
+
+ private Collection<Junk> buildCollection() {
+ Bag<Junk> bag = new HashBag<Junk>();
+ this.populateCollection(bag);
+ return bag;
+ }
+
+ private SimpleListValueModel<Junk> buildListHolder() {
+ return new SimpleListValueModel<Junk>(this.buildList());
+ }
+
+ private List<Junk> buildList() {
+ List<Junk> list = new ArrayList<Junk>();
+ this.populateCollection(list);
+ return list;
+ }
+
+ private void populateCollection(Collection<Junk> c) {
+ c.add(this.foo);
+ c.add(this.bar);
+ c.add(this.baz);
+ c.add(this.joo);
+ c.add(this.jar);
+ c.add(this.jaz);
+ }
+
+
+ // ********** Junk class **********
+
+ private class Junk extends AbstractModel implements Displayable, Comparable<Junk> {
+ private List<String> stuff;
+ public static final String STUFF_LIST = "stuff";
+
+
+ public Junk(String stuffItem) {
+ this.stuff = new ArrayList<String>();
+ this.stuff.add(stuffItem);
+ }
+ public void addStuff(String stuffItem) {
+ this.stuff.add(stuffItem);
+ fireItemAdded(STUFF_LIST, this.stuff.indexOf(stuffItem), stuffItem);
+ }
+
+ public void removeStuff(String stuffItem) {
+ int index = this.stuff.indexOf(stuffItem);
+ this.stuff.remove(stuffItem);
+ fireItemRemoved(STUFF_LIST, index, stuffItem);
+ }
+
+ @Override
+ public String displayString() {
+ return toString();
+ }
+
+ @Override
+ public Icon icon() {
+ return null;
+ }
+
+ @Override
+ public int compareTo(Junk o) {
+ return this.displayString().compareTo(o.displayString());
+ }
+
+ @Override
+ public String toString() {
+ return "Junk(" + this.stuff + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemPropertyListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemPropertyListValueModelAdapterTests.java
new file mode 100644
index 0000000..ed61223
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemPropertyListValueModelAdapterTests.java
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.swing.Icon;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemPropertyListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+@SuppressWarnings("nls")
+public class ItemPropertyListValueModelAdapterTests extends TestCase {
+
+ private Junk foo;
+ private Junk bar;
+ private Junk baz;
+ private Junk joo;
+ private Junk jar;
+ private Junk jaz;
+
+ private Junk tom;
+ private Junk dick;
+ private Junk harry;
+
+ public ItemPropertyListValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.foo = new Junk("this.foo");
+ this.bar = new Junk("this.bar");
+ this.baz = new Junk("this.baz");
+ this.joo = new Junk("this.joo");
+ this.jar = new Junk("this.jar");
+ this.jaz = new Junk("this.jaz");
+
+ this.tom = new Junk("this.tom");
+ this.dick = new Junk("this.dick");
+ this.harry = new Junk("this.harry");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testCollectionSynchronization() {
+ SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+ ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(collectionHolder, Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.add(this.tom);
+ collectionHolder.add(this.dick);
+ collectionHolder.add(this.harry);
+ assertEquals(9, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.remove(this.foo);
+ collectionHolder.remove(this.jar);
+ collectionHolder.remove(this.harry);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.setValues(this.buildCollection());
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+ }
+
+ public void testListSynchronization() {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(listHolder, Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ listHolder.add(6, this.tom);
+ listHolder.add(7, this.dick);
+ listHolder.add(8, this.harry);
+ assertEquals(9, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ listHolder.remove(8);
+ listHolder.remove(0);
+ listHolder.remove(4);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ // test concurrent modification exception
+ listHolder.setListValues(this.buildList());
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+ }
+
+ private void compare(ListValueModel<Junk> listValueModel, List<Junk> list) {
+ assertEquals(listValueModel.size(), list.size());
+ for (int i = 0; i < listValueModel.size(); i++) {
+ assertEquals(listValueModel.get(i), list.get(i));
+ }
+ }
+
+ public void testCollectionSort() {
+ this.verifyCollectionSort(null);
+ }
+
+ public void testListSort() {
+ this.verifyListSort(null);
+ }
+
+ public void testCustomCollectionSort() {
+ this.verifyCollectionSort(this.buildCustomComparator());
+ }
+
+ public void testCustomListSort() {
+ this.verifyListSort(this.buildCustomComparator());
+ }
+
+ private Comparator<Junk> buildCustomComparator() {
+ // sort with reverse order
+ return new Comparator<Junk>() {
+ @Override
+ public int compare(Junk o1, Junk o2) {
+ return o2.displayString().compareTo(o1.displayString());
+ }
+ };
+ }
+
+ private void verifyCollectionSort(Comparator<Junk> comparator) {
+ SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+ ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(new SortedListValueModelAdapter<Junk>(collectionHolder, comparator), Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ collectionHolder.add(this.tom);
+ collectionHolder.add(this.dick);
+ collectionHolder.add(this.harry);
+ assertEquals(9, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ collectionHolder.remove(this.foo);
+ collectionHolder.remove(this.jar);
+ collectionHolder.remove(this.harry);
+ assertEquals(6, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ collectionHolder.setValues(this.buildCollection());
+ assertEquals(6, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+ }
+
+ private void verifyListSort(Comparator<Junk> comparator) {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder, comparator), Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ listHolder.add(0, this.tom);
+ listHolder.add(0, this.dick);
+ listHolder.add(0, this.harry);
+ assertEquals(9, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ listHolder.remove(8);
+ listHolder.remove(4);
+ listHolder.remove(0);
+ listHolder.remove(5);
+ assertEquals(5, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ listHolder.setListValues(this.buildList());
+ assertEquals(6, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+ }
+
+ private void compareSort(ListValueModel<Junk> listValueModel, List<Junk> list, Comparator<Junk> comparator) {
+ SortedSet<Junk> ss = new TreeSet<Junk>(comparator);
+ for (int i = 0; i < listValueModel.size(); i++) {
+ ss.add(listValueModel.get(i));
+ }
+ assertEquals(ss.size(), list.size());
+ for (Iterator<Junk> stream1 = ss.iterator(), stream2 = list.iterator(); stream1.hasNext(); ) {
+ assertEquals(stream1.next(), stream2.next());
+ }
+ }
+
+ public void testHasListeners() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+ assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+ assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+ assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+
+ ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder), Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+ assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+ assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+ assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+ this.verifyHasNoListeners(listValueModel);
+
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(this.foo.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+ assertTrue(this.foo.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+ assertTrue(this.jaz.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+ assertTrue(this.jaz.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+ this.verifyHasListeners(listValueModel);
+
+ listValueModel.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+ assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+ assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+ assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+ this.verifyHasNoListeners(listValueModel);
+ }
+
+ public void testGetSize() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder), Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ this.verifyHasListeners(listValueModel);
+ assertEquals(6, listValueModel.size());
+ assertEquals(6, synchList.size());
+ }
+
+ public void testGet() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new SortedListValueModelWrapper<Junk>(new ItemPropertyListValueModelAdapter<Junk>(listHolder, Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY));
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ this.verifyHasListeners(listValueModel);
+ assertEquals(this.bar, listValueModel.get(0));
+ assertEquals(this.bar, synchList.get(0));
+ this.bar.setName("zzz");
+ assertEquals(this.bar, listValueModel.get(5));
+ assertEquals(this.bar, synchList.get(5));
+ this.bar.setName("this.bar");
+ }
+
+ private void verifyHasNoListeners(ListValueModel<Junk> listValueModel) throws Exception {
+ assertTrue(((AbstractModel) listValueModel).hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private void verifyHasListeners(ListValueModel<Junk> listValueModel) throws Exception {
+ assertTrue(((AbstractModel) listValueModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private SimpleCollectionValueModel<Junk> buildCollectionHolder() {
+ return new SimpleCollectionValueModel<Junk>(this.buildCollection());
+ }
+
+ private Collection<Junk> buildCollection() {
+ Bag<Junk> bag = new HashBag<Junk>();
+ this.populateCollection(bag);
+ return bag;
+ }
+
+ private SimpleListValueModel<Junk> buildListHolder() {
+ return new SimpleListValueModel<Junk>(this.buildList());
+ }
+
+ private List<Junk> buildList() {
+ List<Junk> list = new ArrayList<Junk>();
+ this.populateCollection(list);
+ return list;
+ }
+
+ private void populateCollection(Collection<Junk> c) {
+ c.add(this.foo);
+ c.add(this.bar);
+ c.add(this.baz);
+ c.add(this.joo);
+ c.add(this.jar);
+ c.add(this.jaz);
+ }
+
+
+ // ********** Junk class **********
+
+ private class Junk extends AbstractModel implements Displayable, Comparable<Junk> {
+ private String name;
+ public Junk(String name) {
+ this.name = name;
+ }
+ @Override
+ public String displayString() {
+ return this.name;
+ }
+ @Override
+ public Icon icon() {
+ return null;
+ }
+ public void setName(String name) {
+ Object old = this.name;
+ this.name = name;
+ this.firePropertyChanged(DISPLAY_STRING_PROPERTY, old, name);
+ }
+ @Override
+ public int compareTo(Junk o) {
+ return this.displayString().compareTo(o.displayString());
+ }
+ @Override
+ public String toString() {
+ return "Junk(" + this.name + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemStateListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemStateListValueModelAdapterTests.java
new file mode 100644
index 0000000..6d65012
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemStateListValueModelAdapterTests.java
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemStateListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class ItemStateListValueModelAdapterTests extends TestCase {
+
+ private Junk foo;
+ private Junk bar;
+ private Junk baz;
+ private Junk joo;
+ private Junk jar;
+ private Junk jaz;
+
+ private Junk tom;
+ private Junk dick;
+ private Junk harry;
+
+ public ItemStateListValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.foo = new Junk("this.foo");
+ this.bar = new Junk("this.bar");
+ this.baz = new Junk("this.baz");
+ this.joo = new Junk("this.joo");
+ this.jar = new Junk("this.jar");
+ this.jaz = new Junk("this.jaz");
+
+ this.tom = new Junk("this.tom");
+ this.dick = new Junk("this.dick");
+ this.harry = new Junk("this.harry");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testCollectionSynchronization() {
+ SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+ ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(collectionHolder);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.add(this.tom);
+ collectionHolder.add(this.dick);
+ collectionHolder.add(this.harry);
+ assertEquals(9, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ collectionHolder.remove(this.foo);
+ collectionHolder.remove(this.jar);
+ collectionHolder.remove(this.harry);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+ }
+
+ public void testListSynchronization() {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(listHolder);
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ listHolder.add(6, this.tom);
+ listHolder.add(7, this.dick);
+ listHolder.add(8, this.harry);
+ assertEquals(9, synchList.size());
+ this.compare(listValueModel, synchList);
+
+ listHolder.remove(8);
+ listHolder.remove(0);
+ listHolder.remove(4);
+ assertEquals(6, synchList.size());
+ this.compare(listValueModel, synchList);
+ }
+
+ private void compare(ListValueModel<Junk> listValueModel, List<Junk> list) {
+ assertEquals(listValueModel.size(), list.size());
+ for (int i = 0; i < listValueModel.size(); i++) {
+ assertEquals(listValueModel.get(i), list.get(i));
+ }
+ }
+
+ public void testCollectionSort() {
+ this.verifyCollectionSort(null);
+ }
+
+ public void testListSort() {
+ this.verifyListSort(null);
+ }
+
+ public void testCustomCollectionSort() {
+ this.verifyCollectionSort(this.buildCustomComparator());
+ }
+
+ public void testCustomListSort() {
+ this.verifyListSort(this.buildCustomComparator());
+ }
+
+ private Comparator<Junk> buildCustomComparator() {
+ // sort with reverse order
+ return new Comparator<Junk>() {
+ @Override
+ public int compare(Junk o1, Junk o2) {
+ return o2.compareTo(o1);
+ }
+ };
+ }
+
+ private void verifyCollectionSort(Comparator<Junk> comparator) {
+ SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+ ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(new SortedListValueModelAdapter<Junk>(collectionHolder, comparator));
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ collectionHolder.add(this.tom);
+ collectionHolder.add(this.dick);
+ collectionHolder.add(this.harry);
+ assertEquals(9, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ collectionHolder.remove(this.foo);
+ collectionHolder.remove(this.jar);
+ collectionHolder.remove(this.harry);
+ assertEquals(6, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+ }
+
+ private void verifyListSort(Comparator<Junk> comparator) {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder, comparator));
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertEquals(6, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ listHolder.add(0, this.tom);
+ listHolder.add(0, this.dick);
+ listHolder.add(0, this.harry);
+ assertEquals(9, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+
+ listHolder.remove(8);
+ listHolder.remove(4);
+ listHolder.remove(0);
+ listHolder.remove(5);
+ assertEquals(5, synchList.size());
+ this.compareSort(listValueModel, synchList, comparator);
+ }
+
+ private void compareSort(ListValueModel<Junk> listValueModel, List<Junk> list, Comparator<Junk> comparator) {
+ SortedSet<Junk> ss = new TreeSet<Junk>(comparator);
+ for (int i = 0; i < listValueModel.size(); i++) {
+ ss.add(listValueModel.get(i));
+ }
+ assertEquals(ss.size(), list.size());
+ for (Iterator<Junk> stream1 = ss.iterator(), stream2 = list.iterator(); stream1.hasNext(); ) {
+ assertEquals(stream1.next(), stream2.next());
+ }
+ }
+
+ public void testHasListeners() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyStateChangeListeners());
+ assertFalse(this.foo.hasAnyStateChangeListeners());
+ assertFalse(this.jaz.hasAnyStateChangeListeners());
+ assertFalse(this.jaz.hasAnyStateChangeListeners());
+
+ ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder));
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyStateChangeListeners());
+ assertFalse(this.foo.hasAnyStateChangeListeners());
+ assertFalse(this.jaz.hasAnyStateChangeListeners());
+ assertFalse(this.jaz.hasAnyStateChangeListeners());
+ this.verifyHasNoListeners(listValueModel);
+
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(this.foo.hasAnyStateChangeListeners());
+ assertTrue(this.foo.hasAnyStateChangeListeners());
+ assertTrue(this.jaz.hasAnyStateChangeListeners());
+ assertTrue(this.jaz.hasAnyStateChangeListeners());
+ this.verifyHasListeners(listValueModel);
+
+ listValueModel.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(this.foo.hasAnyStateChangeListeners());
+ assertFalse(this.foo.hasAnyStateChangeListeners());
+ assertFalse(this.jaz.hasAnyStateChangeListeners());
+ assertFalse(this.jaz.hasAnyStateChangeListeners());
+ this.verifyHasNoListeners(listValueModel);
+ }
+
+ public void testGetSize() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder));
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ this.verifyHasListeners(listValueModel);
+ assertEquals(6, listValueModel.size());
+ assertEquals(6, synchList.size());
+ }
+
+ public void testGet() throws Exception {
+ SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+ ListValueModel<Junk> listValueModel = new SortedListValueModelWrapper<Junk>(new ItemStateListValueModelAdapter<Junk>(listHolder));
+ CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+ this.verifyHasListeners(listValueModel);
+ assertEquals(this.bar, listValueModel.get(0));
+ assertEquals(this.bar, synchList.get(0));
+ this.bar.setName("zzz");
+ assertEquals(this.bar, listValueModel.get(5));
+ assertEquals(this.bar, synchList.get(5));
+ this.bar.setName("this.bar");
+ }
+
+ private void verifyHasNoListeners(ListValueModel<Junk> listValueModel) throws Exception {
+ assertTrue(((AbstractModel) listValueModel).hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private void verifyHasListeners(ListValueModel<Junk> listValueModel) throws Exception {
+ assertTrue(((AbstractModel) listValueModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private SimpleCollectionValueModel<Junk> buildCollectionHolder() {
+ return new SimpleCollectionValueModel<Junk>(this.buildCollection());
+ }
+
+ private Collection<Junk> buildCollection() {
+ Bag<Junk> bag = new HashBag<Junk>();
+ this.populateCollection(bag);
+ return bag;
+ }
+
+ private SimpleListValueModel<Junk> buildListHolder() {
+ return new SimpleListValueModel<Junk>(this.buildList());
+ }
+
+ private List<Junk> buildList() {
+ List<Junk> list = new ArrayList<Junk>();
+ this.populateCollection(list);
+ return list;
+ }
+
+ private void populateCollection(Collection<Junk> c) {
+ c.add(this.foo);
+ c.add(this.bar);
+ c.add(this.baz);
+ c.add(this.joo);
+ c.add(this.jar);
+ c.add(this.jaz);
+ }
+
+ // ********** Junk class **********
+ private class Junk extends AbstractModel implements Comparable<Junk> {
+ private String name;
+ public Junk(String name) {
+ this.name = name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ this.fireStateChanged();
+ }
+ @Override
+ public int compareTo(Junk j) {
+ return this.name.compareTo(j.name);
+ }
+ @Override
+ public String toString() {
+ return "Junk(" + this.name + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ListCollectionValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ListCollectionValueModelAdapterTests.java
new file mode 100644
index 0000000..0542321
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ListCollectionValueModelAdapterTests.java
@@ -0,0 +1,288 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.JList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.iterator.IteratorTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.CollectionAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.CollectionChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListCollectionValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class ListCollectionValueModelAdapterTests extends TestCase {
+
+ CollectionValueModel<String> adapter;
+ private SimpleListValueModel<String> wrappedListHolder;
+ private List<String> wrappedList;
+
+ public ListCollectionValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.wrappedList = new ArrayList<String>();
+ this.wrappedListHolder = new SimpleListValueModel<String>(this.wrappedList);
+ this.adapter = new ListCollectionValueModelAdapter<String>(this.wrappedListHolder);
+ }
+
+ private Collection<String> wrappedCollection() {
+ return CollectionTools.collection(this.wrappedList.iterator());
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testIterator() {
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {
+ // override failure
+ }
+ });
+ this.wrappedListHolder.add(0, "foo");
+ this.wrappedListHolder.add(1, "bar");
+ this.wrappedListHolder.add(2, "baz");
+ Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(3, adapterCollection.size());
+ assertEquals(this.wrappedCollection(), adapterCollection);
+ }
+
+ public void testStaleValues() {
+ CollectionChangeListener listener = new TestListener() {
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {/* OK */}
+ };
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
+ this.wrappedListHolder.add(0, "foo");
+ this.wrappedListHolder.add(1, "bar");
+ this.wrappedListHolder.add(2, "baz");
+ Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(3, adapterCollection.size());
+ assertEquals(this.wrappedCollection(), adapterCollection);
+
+ this.adapter.removeCollectionChangeListener(CollectionValueModel.VALUES, listener);
+ adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(0, adapterCollection.size());
+ assertEquals(new HashBag<String>(), adapterCollection);
+
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
+ adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(3, adapterCollection.size());
+ assertEquals(this.wrappedCollection(), adapterCollection);
+ }
+
+ public void testAdd() {
+ Bag<String> synchCollection = new CoordinatedBag<String>(this.adapter);
+ List<String> synchList = new CoordinatedList<String>(this.wrappedListHolder);
+ this.wrappedListHolder.add(0, "foo");
+ assertTrue(this.wrappedList.contains("foo"));
+ this.wrappedListHolder.add(1, "bar");
+ this.wrappedListHolder.add(2, "baz");
+ this.wrappedListHolder.add(3, "joo");
+ this.wrappedListHolder.add(4, "jar");
+ this.wrappedListHolder.add(5, "jaz");
+ assertEquals(6, this.wrappedList.size());
+
+ Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(this.wrappedCollection(), adapterCollection);
+ assertEquals(this.wrappedCollection(), CollectionTools.collection(synchList.iterator()));
+ assertEquals(this.wrappedCollection(), synchCollection);
+ }
+
+ public void testRemove() {
+ Bag<String> synchCollection = new CoordinatedBag<String>(this.adapter);
+ List<String> synchList = new CoordinatedList<String>(this.wrappedListHolder);
+ this.wrappedListHolder.add(0, "foo");
+ this.wrappedListHolder.add(1, "bar");
+ this.wrappedListHolder.add(2, "baz");
+ this.wrappedListHolder.add(3, "joo");
+ this.wrappedListHolder.add(4, "jar");
+ this.wrappedListHolder.add(5, "jaz");
+ assertEquals("jaz", this.wrappedListHolder.remove(5));
+ assertFalse(this.wrappedList.contains("jaz"));
+ assertEquals("foo", this.wrappedListHolder.remove(0));
+ assertFalse(this.wrappedList.contains("foo"));
+ assertEquals(4, this.wrappedList.size());
+
+ Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(this.wrappedCollection(), adapterCollection);
+ assertEquals(this.wrappedCollection(), CollectionTools.collection(synchList.iterator()));
+ assertEquals(this.wrappedCollection(), synchCollection);
+ }
+
+ public void testListSynch() {
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {
+ // override failure
+ }
+ @Override
+ public void itemsRemoved(CollectionRemoveEvent e) {
+ // override failure
+ }
+ });
+ this.wrappedListHolder.add(0, "foo");
+ this.wrappedListHolder.add(1, "bar");
+ this.wrappedListHolder.add(2, "baz");
+ this.wrappedListHolder.add(3, "joo");
+ this.wrappedListHolder.add(4, "jar");
+ this.wrappedListHolder.add(5, "jaz");
+ this.wrappedListHolder.remove(5);
+ assertFalse(this.wrappedList.contains("jaz"));
+ this.wrappedListHolder.remove(0);
+ assertFalse(this.wrappedList.contains("foo"));
+ assertEquals(4, this.wrappedList.size());
+
+ Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(this.wrappedCollection(), adapterCollection);
+ }
+
+ public void testReplace() {
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {
+ // override failure
+ }
+ @Override
+ public void itemsRemoved(CollectionRemoveEvent e) {
+ // override failure
+ }
+ });
+ this.wrappedListHolder.add(0, "foo");
+ this.wrappedListHolder.add(1, "bar");
+ this.wrappedListHolder.add(2, "baz");
+ Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(3, adapterCollection.size());
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+ @Override
+ public void itemsRemoved(CollectionRemoveEvent e) {
+ assertEquals("foo", e.getItems().iterator().next());
+ assertFalse(IteratorTools.contains(ListCollectionValueModelAdapterTests.this.adapter.iterator(), "joo"));
+ assertEquals(2, ListCollectionValueModelAdapterTests.this.adapter.size());
+ }
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {
+ assertEquals("joo", e.getItems().iterator().next());
+ assertEquals(3, ListCollectionValueModelAdapterTests.this.adapter.size());
+ }
+ });
+ this.wrappedListHolder.set(0, "joo");
+ adapterCollection = CollectionTools.collection(this.adapter.iterator());
+ assertEquals(3, adapterCollection.size());
+ assertEquals(this.wrappedCollection(), adapterCollection);
+ }
+
+ public void testHasListeners() {
+ assertFalse(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ CoordinatedBag<String> synchCollection = new CoordinatedBag<String>(this.adapter);
+ assertTrue(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ this.adapter.removeCollectionChangeListener(CollectionValueModel.VALUES, synchCollection);
+ assertFalse(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+
+ ChangeListener cl = new ChangeAdapter();
+ this.adapter.addChangeListener(cl);
+ assertTrue(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ this.adapter.removeChangeListener(cl);
+ assertFalse(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ }
+
+ public void testListChangedToEmpty() {
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {/* OK */}
+ @Override
+ public void collectionCleared(CollectionClearEvent e) {/* OK */}
+ });
+ this.wrappedListHolder.add(0, "foo");
+ this.wrappedListHolder.add(1, "bar");
+ this.wrappedListHolder.add(2, "baz");
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+ this.wrappedListHolder.setListValues(new ArrayList<String>());
+ assertEquals(0, jList.getModel().getSize());
+ }
+
+ public void testCollectionChangedFromEmpty() {
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {/* OK */}
+ @Override
+ public void itemsRemoved(CollectionRemoveEvent e) {/* OK */}
+ });
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+
+ ArrayList<String> list = new ArrayList<String>();
+ list.add("foo");
+ list.add("bar");
+ this.wrappedListHolder.setListValues(list);
+ assertEquals(2, jList.getModel().getSize());
+ }
+
+ public void testCollectionChangedFromEmptyToEmpty() {
+ this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {/* OK */}
+ @Override
+ public void itemsRemoved(CollectionRemoveEvent e) {/* OK */}
+ });
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+
+ ArrayList<String> list = new ArrayList<String>();
+ this.wrappedListHolder.setListValues(list);
+ assertEquals(0, jList.getModel().getSize());
+ }
+
+
+ // ********** inner class **********
+
+ class TestListener implements CollectionChangeListener {
+ @Override
+ public void itemsAdded(CollectionAddEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsRemoved(CollectionRemoveEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void collectionCleared(CollectionClearEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void collectionChanged(CollectionChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyCollectionValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyCollectionValueModelAdapterTests.java
index 0526590..ec77da5 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyCollectionValueModelAdapterTests.java
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyCollectionValueModelAdapterTests.java
@@ -14,6 +14,7 @@
package org.eclipse.persistence.tools.utility.tests.model.value;
import java.util.Collection;
+import javax.swing.JList;
import junit.framework.TestCase;
import org.eclipse.persistence.tools.utility.collection.CollectionTools;
import org.eclipse.persistence.tools.utility.collection.HashBag;
@@ -30,6 +31,7 @@
import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
import org.eclipse.persistence.tools.utility.model.value.PropertyCollectionValueModelAdapter;
import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
import org.eclipse.persistence.tools.utility.tests.TestTools;
@SuppressWarnings("nls")
@@ -116,9 +118,9 @@
public void itemsRemoved(CollectionRemoveEvent e) {/* OK */}
});
this.wrappedValueHolder.setValue("foo");
-// JList jList = new JList(new ListModelAdapter(this.adapter));
+ JList jList = new JList(new ListModelAdapter(this.adapter));
this.wrappedValueHolder.setValue(null);
-// assertEquals(0, jList.getModel().getSize());
+ assertEquals(0, jList.getModel().getSize());
}
public void testCollectionChangedFromEmpty() {
@@ -126,18 +128,18 @@
@Override
public void itemsAdded(CollectionAddEvent e) {/* OK */}
});
-// JList jList = new JList(new ListModelAdapter(this.adapter));
+ JList jList = new JList(new ListModelAdapter(this.adapter));
this.wrappedValueHolder.setValue("foo");
-// assertEquals(1, jList.getModel().getSize());
+ assertEquals(1, jList.getModel().getSize());
}
public void testCollectionChangedFromEmptyToEmpty() {
this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener());
-// JList jList = new JList(new ListModelAdapter(this.adapter));
+ JList jList = new JList(new ListModelAdapter(this.adapter));
this.wrappedValueHolder.setValue(null);
-// assertEquals(0, jList.getModel().getSize());
+ assertEquals(0, jList.getModel().getSize());
}
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyListValueModelAdapterTests.java
new file mode 100644
index 0000000..a572c93
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyListValueModelAdapterTests.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.JList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.iterator.SingleElementIterator;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class PropertyListValueModelAdapterTests extends TestCase {
+
+ private ListValueModel<String> adapter;
+ private ModifiablePropertyValueModel<String> wrappedValueHolder;
+
+ public PropertyListValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.wrappedValueHolder = new SimplePropertyValueModel<String>();
+ this.adapter = new PropertyListValueModelAdapter<String>(this.wrappedValueHolder);
+ }
+
+ private Collection<String> wrappedList() {
+ return ListTools.list(new SingleElementIterator<String>(this.wrappedValueHolder.getValue()));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testIterator() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) {/* OK */}
+ });
+ assertFalse(this.adapter.iterator().hasNext());
+ this.wrappedValueHolder.setValue("foo");
+ List<String> adapterList = ListTools.list(this.adapter.iterator());
+ assertEquals(1, adapterList.size());
+ assertEquals(this.wrappedList(), adapterList);
+ assertEquals("foo", adapterList.iterator().next());
+ }
+
+ public void testGetInt() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) {/* OK */}
+ });
+ this.wrappedValueHolder.setValue("foo");
+ assertEquals("foo", this.adapter.get(0));
+ }
+
+ public void testToArray1() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) {/* OK */}
+ });
+ this.wrappedValueHolder.setValue("foo");
+ Object[] array = this.adapter.toArray();
+ assertEquals("foo", array[0]);
+ assertEquals(1, array.length);
+ }
+
+ public void testToArray2() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener());
+ Object[] array = this.adapter.toArray();
+ assertEquals(0, array.length);
+ }
+
+ public void testStaleValue() {
+ ListChangeListener listener = new TestListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) {/* OK */}
+ };
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ this.wrappedValueHolder.setValue("foo");
+ List<String> adapterList = ListTools.list(this.adapter.iterator());
+ assertEquals(1, adapterList.size());
+ assertEquals(this.wrappedList(), adapterList);
+ assertEquals("foo", adapterList.iterator().next());
+
+ this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, listener);
+ adapterList = ListTools.list(this.adapter.iterator());
+ assertEquals(0, adapterList.size());
+ assertEquals(new ArrayList<String>(), adapterList);
+
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+ adapterList = ListTools.list(this.adapter.iterator());
+ assertEquals(1, adapterList.size());
+ assertEquals(this.wrappedList(), adapterList);
+ assertEquals("foo", adapterList.iterator().next());
+ }
+
+ public void testHasListeners() {
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ CoordinatedList<String> synchList = new CoordinatedList<String>(this.adapter);
+ assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ ChangeListener cl = new ChangeAdapter();
+ this.adapter.addChangeListener(cl);
+ assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.adapter.removeChangeListener(cl);
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ public void testListChangedToEmpty() {
+ this.wrappedValueHolder.setValue("foo");
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {/* OK */}
+ });
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+ this.wrappedValueHolder.setValue(null);
+ assertEquals(0, jList.getModel().getSize());
+ }
+
+ public void testListChangedFromEmpty() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) {/* OK */}
+ });
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+
+ this.wrappedValueHolder.setValue("foo");
+ assertEquals(1, jList.getModel().getSize());
+ }
+
+ public void testListItemChanged() {
+ this.wrappedValueHolder.setValue("foo");
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {/* OK */}
+ });
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+ assertEquals(1, jList.getModel().getSize());
+ assertEquals("foo", jList.getModel().getElementAt(0));
+
+ this.wrappedValueHolder.setValue("bar");
+ assertEquals(1, jList.getModel().getSize());
+ assertEquals("bar", jList.getModel().getElementAt(0));
+ }
+
+ public void testListChangedFromEmptyToEmpty() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener());
+ JList jList = new JList(new ListModelAdapter(this.adapter));
+
+ this.wrappedValueHolder.setValue(null);
+ assertEquals(0, jList.getModel().getSize());
+ }
+
+
+ // ********** member class **********
+
+ static class TestListener implements ListChangeListener {
+ @Override
+ public void listChanged(ListChangeEvent event) {
+ fail("unexpected event");
+ }
+ @Override
+ public void listCleared(ListClearEvent event) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsAdded(ListAddEvent event) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsMoved(ListMoveEvent event) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelAdapterTests.java
new file mode 100644
index 0000000..c7a042c
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelAdapterTests.java
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.TreeSet;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ReverseComparator;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class SortedListValueModelAdapterTests extends TestCase {
+ private SortedListValueModelAdapter<String> adapter;
+ private SimpleCollectionValueModel<String> wrappedCollectionHolder;
+ private Collection<String> wrappedCollection;
+
+
+ public SortedListValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.wrappedCollection = new HashBag<String>();
+ this.wrappedCollectionHolder = new SimpleCollectionValueModel<String>(this.wrappedCollection);
+ this.adapter = new SortedListValueModelAdapter<String>(this.wrappedCollectionHolder);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ private void verifyList(Collection<String> expected, ListValueModel<String> actual) {
+ this.verifyList(expected, actual, null);
+ }
+
+ private void verifyList(Collection<String> expected, ListValueModel<String> actual, Comparator<String> comparator) {
+ Collection<String> sortedSet = new TreeSet<String>(comparator);
+ sortedSet.addAll(expected);
+ List<String> expectedList = new ArrayList<String>(sortedSet);
+ List<String> actualList = ListTools.list(actual.iterator());
+ assertEquals(expectedList, actualList);
+ }
+
+ public void testAdd() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+ });
+ this.wrappedCollectionHolder.add("foo");
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ assertEquals(3, this.adapter.size());
+ this.verifyList(this.wrappedCollection, this.adapter);
+ }
+
+ public void testAddItem() {
+ List<String> synchList = new CoordinatedList<String>(this.adapter);
+ Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+ this.wrappedCollectionHolder.add("foo");
+ assertTrue(this.wrappedCollection.contains("foo"));
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ this.wrappedCollectionHolder.add("joo");
+ this.wrappedCollectionHolder.add("jar");
+ this.wrappedCollectionHolder.add("jaz");
+ assertEquals(6, this.wrappedCollection.size());
+
+ this.verifyList(this.wrappedCollection, this.adapter);
+ assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+ assertEquals(this.wrappedCollection, synchCollection);
+ }
+
+ public void testRemoveItem() {
+ List<String> synchList = new CoordinatedList<String>(this.adapter);
+ Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+ this.wrappedCollectionHolder.add("foo");
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ this.wrappedCollectionHolder.add("joo");
+ this.wrappedCollectionHolder.add("jar");
+ this.wrappedCollectionHolder.add("jaz");
+ this.wrappedCollectionHolder.remove("jaz");
+ assertFalse(this.wrappedCollection.contains("jaz"));
+ this.wrappedCollectionHolder.remove("foo");
+ assertFalse(this.wrappedCollection.contains("foo"));
+ assertEquals(4, this.wrappedCollection.size());
+
+ this.verifyList(this.wrappedCollection, this.adapter);
+ assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+ assertEquals(this.wrappedCollection, synchCollection);
+ }
+
+ public void testListSynch() {
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+ });
+ this.wrappedCollectionHolder.add("foo");
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ this.wrappedCollectionHolder.add("joo");
+ this.wrappedCollectionHolder.add("jar");
+ this.wrappedCollectionHolder.add("jaz");
+ this.wrappedCollectionHolder.remove("jaz");
+ assertFalse(this.wrappedCollection.contains("jaz"));
+ this.wrappedCollectionHolder.remove("foo");
+ assertFalse(this.wrappedCollection.contains("foo"));
+ assertEquals(4, this.wrappedCollection.size());
+
+ this.verifyList(this.wrappedCollection, this.adapter);
+ }
+
+ public void testSetComparator() {
+ List<String> synchList = new CoordinatedList<String>(this.adapter);
+ Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+ this.wrappedCollectionHolder.add("foo");
+ assertTrue(this.wrappedCollection.contains("foo"));
+ this.wrappedCollectionHolder.add("bar");
+ this.wrappedCollectionHolder.add("baz");
+ this.wrappedCollectionHolder.add("joo");
+ this.wrappedCollectionHolder.add("jar");
+ this.wrappedCollectionHolder.add("jaz");
+ assertEquals(6, this.wrappedCollection.size());
+
+ this.verifyList(this.wrappedCollection, this.adapter);
+ assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+ assertEquals(this.wrappedCollection, synchCollection);
+
+ this.adapter.setComparator(new ReverseComparator<String>());
+ this.verifyList(this.wrappedCollection, this.adapter, new ReverseComparator<String>());
+ assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+ assertEquals(this.wrappedCollection, synchCollection);
+ }
+
+ public void testHasListeners() {
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ CoordinatedList<String> synchList = new CoordinatedList<String>(this.adapter);
+ assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ ChangeListener cl = new ChangeAdapter();
+ this.adapter.addChangeListener(cl);
+ assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.adapter.removeChangeListener(cl);
+ assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ public void testCollectionChange() {
+ this.wrappedCollectionHolder.add("fred");
+ this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+ });
+ this.wrappedCollectionHolder.setValues(Arrays.asList(new String[] {"foo", "bar", "baz"}));
+ assertEquals(3, this.adapter.size());
+ this.verifyList(this.wrappedCollection, this.adapter);
+ }
+
+ class TestListChangeListener implements ListChangeListener {
+ @Override
+ public void itemsAdded(ListAddEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsMoved(ListMoveEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void listCleared(ListClearEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void listChanged(ListChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelWrapperTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelWrapperTests.java
new file mode 100644
index 0000000..8a8ebb4
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelWrapperTests.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.TreeSet;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ReverseComparator;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class SortedListValueModelWrapperTests extends TestCase {
+ private List<String> list;
+ private SimpleListValueModel<String> listModel;
+ private SortedListValueModelWrapper<String> sortedListModel;
+
+
+ public SortedListValueModelWrapperTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.list = new ArrayList<String>();
+ this.listModel = new SimpleListValueModel<String>(this.list);
+ this.sortedListModel = new SortedListValueModelWrapper<String>(this.listModel);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ private void verifyList(Collection<String> expected, ListValueModel<String> actual) {
+ this.verifyList(expected, actual, null);
+ }
+
+ private void verifyList(Collection<String> expected, ListValueModel<String> actual, Comparator<String> comparator) {
+ Collection<String> sortedSet = new TreeSet<String>(comparator);
+ sortedSet.addAll(expected);
+ List<String> expectedList = new ArrayList<String>(sortedSet);
+ List<String> actualList = ListTools.list(actual);
+ assertEquals(expectedList, actualList);
+ }
+
+ public void testAdd() {
+ this.sortedListModel.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+ });
+ this.listModel.add("foo");
+ this.listModel.add("bar");
+ this.listModel.add("baz");
+ assertEquals(3, this.sortedListModel.size());
+ this.verifyList(this.list, this.sortedListModel);
+ }
+
+ public void testAddItem() {
+ List<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+ List<String> synchList = new CoordinatedList<String>(this.listModel);
+ this.listModel.add("foo");
+ assertTrue(this.list.contains("foo"));
+ this.listModel.add("bar");
+ this.listModel.add("baz");
+ this.listModel.add("joo");
+ this.listModel.add("jar");
+ this.listModel.add("jaz");
+ assertEquals(6, this.list.size());
+
+ this.verifyList(this.list, this.sortedListModel);
+ assertEquals(this.list, synchList);
+ assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+ }
+
+ public void testRemoveItem() {
+ List<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+ List<String> synchList = new CoordinatedList<String>(this.listModel);
+ this.listModel.add("foo");
+ this.listModel.add("bar");
+ this.listModel.add("baz");
+ this.listModel.add("joo");
+ this.listModel.add("jar");
+ this.listModel.add("jaz");
+ this.listModel.remove("jaz");
+ assertFalse(this.list.contains("jaz"));
+ this.listModel.remove("foo");
+ assertFalse(this.list.contains("foo"));
+ assertEquals(4, this.list.size());
+
+ this.verifyList(this.list, this.sortedListModel);
+ assertEquals(this.list, synchList);
+ assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+ }
+
+ public void testReplaceItem() {
+ List<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+ List<String> synchList = new CoordinatedList<String>(this.listModel);
+ this.listModel.add("foo");
+ assertTrue(this.list.contains("foo"));
+ this.listModel.add("bar");
+ this.listModel.add("baz");
+ this.listModel.add("joo");
+ this.listModel.add("jar");
+ this.listModel.add("jaz");
+ assertEquals(6, this.list.size());
+ this.listModel.set(3, "ttt");
+ this.listModel.set(4, "xxx");
+ assertTrue(this.list.contains("xxx"));
+
+ this.verifyList(this.list, this.sortedListModel);
+ assertEquals(this.list, synchList);
+ assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+ }
+
+ public void testListSynch() {
+ this.sortedListModel.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent e) {/* OK */}
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+ });
+ this.listModel.add("foo");
+ this.listModel.add("bar");
+ this.listModel.add("baz");
+ this.listModel.add("joo");
+ this.listModel.add("jar");
+ this.listModel.add("jaz");
+ this.listModel.remove("jaz");
+ assertFalse(this.list.contains("jaz"));
+ this.listModel.remove("foo");
+ assertFalse(this.list.contains("foo"));
+ assertEquals(4, this.list.size());
+
+ this.verifyList(this.list, this.sortedListModel);
+ }
+
+ public void testSetComparator() {
+ List<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+ List<String> synchList = new CoordinatedList<String>(this.listModel);
+ this.listModel.add("foo");
+ assertTrue(this.list.contains("foo"));
+ this.listModel.add("bar");
+ this.listModel.add("baz");
+ this.listModel.add("joo");
+ this.listModel.add("jar");
+ this.listModel.add("jaz");
+ assertEquals(6, this.list.size());
+
+ this.verifyList(this.list, this.sortedListModel);
+ assertEquals(this.list, synchList);
+ assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+
+ this.sortedListModel.setComparator(new ReverseComparator<String>());
+ this.verifyList(this.list, this.sortedListModel, new ReverseComparator<String>());
+ assertEquals(this.list, synchList);
+ }
+
+ public void testHasListeners() {
+ assertFalse(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ CoordinatedList<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+ assertTrue(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.sortedListModel.removeListChangeListener(ListValueModel.LIST_VALUES, sortedSynchList);
+ assertFalse(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ ChangeListener cl = new ChangeAdapter();
+ this.sortedListModel.addChangeListener(cl);
+ assertTrue(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.sortedListModel.removeChangeListener(cl);
+ assertFalse(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ public void testListChange() {
+ this.listModel.add("fred");
+ this.sortedListModel.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+ @Override
+ public void listChanged(ListChangeEvent e) {/* OK */}
+ });
+ this.listModel.setListValues(Arrays.asList(new String[] {"foo", "bar", "baz"}));
+ assertEquals(3, this.sortedListModel.size());
+ this.verifyList(this.list, this.sortedListModel);
+ }
+
+ class TestListChangeListener implements ListChangeListener {
+ @Override
+ public void itemsAdded(ListAddEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsReplaced(ListReplaceEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void itemsMoved(ListMoveEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void listCleared(ListClearEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void listChanged(ListChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/UtilityModelValueTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/UtilityModelValueTests.java
index d257def..3597486 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/UtilityModelValueTests.java
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/UtilityModelValueTests.java
@@ -16,7 +16,7 @@
import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.persistence.tools.utility.tests.model.value.prefs.UtilityModelValuePrefsTests;
-//import org.eclipse.persistence.tools.utility.tests.model.value.swing.UtilityModelValueSwingTests;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.UtilityModelValueSwingTests;
public class UtilityModelValueTests {
@@ -24,42 +24,42 @@
TestSuite suite = new TestSuite(UtilityModelValueTests.class.getPackage().getName());
suite.addTest(UtilityModelValuePrefsTests.suite());
-// suite.addTest(UtilityModelValueSwingTests.suite());
+ suite.addTest(UtilityModelValueSwingTests.suite());
suite.addTestSuite(BufferedModifiablePropertyValueModelTests.class);
suite.addTestSuite(CachingTransformationPropertyValueModelTests.class);
suite.addTestSuite(CollectionAspectAdapterTests.class);
-// suite.addTestSuite(CollectionListValueModelAdapterTests.class);
+ suite.addTestSuite(CollectionListValueModelAdapterTests.class);
suite.addTestSuite(CollectionPropertyValueModelAdapterTests.class);
suite.addTestSuite(CompositeBooleanPropertyValueModelTests.class);
suite.addTestSuite(CompositeCollectionValueModelTests.class);
-// suite.addTestSuite(CompositeListValueModelTests.class);
+ suite.addTestSuite(CompositeListValueModelTests.class);
suite.addTestSuite(CompositePropertyValueModelTests.class);
suite.addTestSuite(DoubleModifiablePropertyValueModelTests.class);
suite.addTestSuite(DoublePropertyValueModelTests.class);
suite.addTestSuite(ExtendedListValueModelWrapperTests.class);
suite.addTestSuite(FilteringCollectionValueModelTests.class);
suite.addTestSuite(FilteringPropertyValueModelTests.class);
-// suite.addTestSuite(ItemCollectionListValueModelAdapterTests.class);
-// suite.addTestSuite(ItemListListValueModelAdapterTests.class);
-// suite.addTestSuite(ItemPropertyListValueModelAdapterTests.class);
-// suite.addTestSuite(ItemStateListValueModelAdapterTests.class);
+ suite.addTestSuite(ItemCollectionListValueModelAdapterTests.class);
+ suite.addTestSuite(ItemListListValueModelAdapterTests.class);
+ suite.addTestSuite(ItemPropertyListValueModelAdapterTests.class);
+ suite.addTestSuite(ItemStateListValueModelAdapterTests.class);
suite.addTestSuite(ListAspectAdapterTests.class);
-// suite.addTestSuite(ListCollectionValueModelAdapterTests.class);
+ suite.addTestSuite(ListCollectionValueModelAdapterTests.class);
suite.addTestSuite(ListCuratorTests.class);
suite.addTestSuite(NullCollectionValueModelTests.class);
suite.addTestSuite(NullListValueModelTests.class);
suite.addTestSuite(NullPropertyValueModelTests.class);
suite.addTestSuite(PropertyAspectAdapterTests.class);
suite.addTestSuite(PropertyCollectionValueModelAdapterTests.class);
-// suite.addTestSuite(PropertyListValueModelAdapterTests.class);
+ suite.addTestSuite(PropertyListValueModelAdapterTests.class);
suite.addTestSuite(ReadOnlyModifiablePropertyValueModelWrapperTests.class);
suite.addTestSuite(SetCollectionValueModelTests.class);
suite.addTestSuite(SimpleCollectionValueModelTests.class);
suite.addTestSuite(SimpleListValueModelTests.class);
suite.addTestSuite(SimplePropertyValueModelTests.class);
-// suite.addTestSuite(SortedListValueModelAdapterTests.class);
-// suite.addTestSuite(SortedListValueModelWrapperTests.class);
+ suite.addTestSuite(SortedListValueModelAdapterTests.class);
+ suite.addTestSuite(SortedListValueModelWrapperTests.class);
suite.addTestSuite(StaticCollectionValueModelTests.class);
suite.addTestSuite(StaticListValueModelTests.class);
suite.addTestSuite(StaticValueModelTests.class);
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterTests.java
new file mode 100644
index 0000000..fc99c76
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterTests.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.ButtonModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.CheckBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class CheckBoxModelAdapterTests extends TestCase {
+ private ModifiablePropertyValueModel<Boolean> booleanHolder;
+ private ButtonModel buttonModelAdapter;
+ boolean eventFired;
+
+ public CheckBoxModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.booleanHolder = new SimplePropertyValueModel<Boolean>(Boolean.TRUE);
+ this.buttonModelAdapter = new CheckBoxModelAdapter(this.booleanHolder) {
+ @Override
+ protected PropertyChangeListener buildBooleanChangeListener() {
+ return this.buildBooleanChangeListener_();
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testSetSelected() throws Exception {
+ this.eventFired = false;
+ this.buttonModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ CheckBoxModelAdapterTests.this.eventFired = true;
+ }
+ });
+ this.buttonModelAdapter.setSelected(false);
+ assertTrue(this.eventFired);
+ assertEquals(Boolean.FALSE, this.booleanHolder.getValue());
+ }
+
+ public void testSetValue() throws Exception {
+ this.eventFired = false;
+ this.buttonModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ CheckBoxModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertTrue(this.buttonModelAdapter.isSelected());
+ this.booleanHolder.setValue(Boolean.FALSE);
+ assertTrue(this.eventFired);
+ assertFalse(this.buttonModelAdapter.isSelected());
+ }
+
+ public void testDefaultValue() throws Exception {
+ this.eventFired = false;
+ this.buttonModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ CheckBoxModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertTrue(this.buttonModelAdapter.isSelected());
+ this.booleanHolder.setValue(null);
+ assertTrue(this.eventFired);
+ assertFalse(this.buttonModelAdapter.isSelected());
+
+ this.eventFired = false;
+ this.booleanHolder.setValue(Boolean.FALSE);
+ assertFalse(this.eventFired);
+ assertFalse(this.buttonModelAdapter.isSelected());
+ }
+
+ public void testHasListeners() throws Exception {
+ SimplePropertyValueModel<Boolean> localBooleanHolder = (SimplePropertyValueModel<Boolean>) this.booleanHolder;
+ assertFalse(localBooleanHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.buttonModelAdapter);
+
+ ChangeListener listener = new TestChangeListener();
+ this.buttonModelAdapter.addChangeListener(listener);
+ assertTrue(localBooleanHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasListeners(this.buttonModelAdapter);
+
+ this.buttonModelAdapter.removeChangeListener(listener);
+ assertFalse(localBooleanHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.buttonModelAdapter);
+ }
+
+ private void verifyHasNoListeners(Object model) throws Exception {
+ EventListenerList listenerList = (EventListenerList) ObjectTools.get(model, "listenerList");
+ assertEquals(0, listenerList.getListenerList().length);
+ }
+
+ private void verifyHasListeners(Object model) throws Exception {
+ EventListenerList listenerList = (EventListenerList) ObjectTools.get(model, "listenerList");
+ assertFalse(listenerList.getListenerList().length == 0);
+ }
+
+
+ // ********** member class **********
+ private class TestChangeListener implements ChangeListener {
+ TestChangeListener() {
+ super();
+ }
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterUITest.java
new file mode 100644
index 0000000..18210e8
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterUITest.java
@@ -0,0 +1,322 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.CheckBoxModelAdapter;
+
+/**
+ * Play around with a set of check boxes.
+ */
+@SuppressWarnings("nls")
+public class CheckBoxModelAdapterUITest {
+
+ private TestModel testModel;
+ private ModifiablePropertyValueModel<TestModel> testModelHolder;
+ private ModifiablePropertyValueModel<Boolean> flag1Holder;
+ private ModifiablePropertyValueModel<Boolean> flag2Holder;
+ private ModifiablePropertyValueModel<Boolean> notFlag2Holder;
+ private ButtonModel flag1ButtonModel;
+ private ButtonModel flag2ButtonModel;
+ private ButtonModel notFlag2ButtonModel;
+
+ public static void main(String[] args) throws Exception {
+ new CheckBoxModelAdapterUITest().exec();
+ }
+
+ private CheckBoxModelAdapterUITest() {
+ super();
+ }
+
+ private void exec() throws Exception {
+ this.testModel = new TestModel(true, true);
+ this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+ this.flag1Holder = this.buildFlag1Holder(this.testModelHolder);
+ this.flag1ButtonModel = this.buildCheckBoxModelAdapter(this.flag1Holder);
+ this.flag2Holder = this.buildFlag2Holder(this.testModelHolder);
+ this.flag2ButtonModel = this.buildCheckBoxModelAdapter(this.flag2Holder);
+ this.notFlag2Holder = this.buildNotFlag2Holder(this.testModelHolder);
+ this.notFlag2ButtonModel = this.buildCheckBoxModelAdapter(this.notFlag2Holder);
+ this.openWindow();
+ }
+
+ private ModifiablePropertyValueModel<Boolean> buildFlag1Holder(PropertyValueModel<TestModel> vm) {
+ return new PropertyAspectAdapter<TestModel, Boolean>(vm, TestModel.FLAG1_PROPERTY) {
+ @Override
+ protected Boolean buildValue_() {
+ return Boolean.valueOf(this.subject.isFlag1());
+ }
+ @Override
+ protected void setValue_(Boolean value) {
+ this.subject.setFlag1(value.booleanValue());
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Boolean> buildFlag2Holder(PropertyValueModel<TestModel> vm) {
+ return new PropertyAspectAdapter<TestModel, Boolean>(vm, TestModel.FLAG2_PROPERTY) {
+ @Override
+ protected Boolean buildValue_() {
+ return Boolean.valueOf(this.subject.isFlag2());
+ }
+ @Override
+ protected void setValue_(Boolean value) {
+ this.subject.setFlag2(value.booleanValue());
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Boolean> buildNotFlag2Holder(PropertyValueModel<TestModel> vm) {
+ return new PropertyAspectAdapter<TestModel, Boolean>(vm, TestModel.NOT_FLAG2_PROPERTY) {
+ @Override
+ protected Boolean buildValue_() {
+ return Boolean.valueOf(this.subject.isNotFlag2());
+ }
+ @Override
+ protected void setValue_(Boolean value) {
+ this.subject.setNotFlag2(value.booleanValue());
+ }
+ };
+ }
+
+ private ButtonModel buildCheckBoxModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder) {
+ return new CheckBoxModelAdapter(booleanHolder);
+ }
+
+ private void openWindow() {
+ JFrame window = new JFrame(this.getClass().getName());
+ window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ window.addWindowListener(this.buildWindowListener());
+ window.getContentPane().add(this.buildMainPanel(), "Center");
+ window.setSize(400, 100);
+ window.setVisible(true);
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private Component buildMainPanel() {
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(this.buildCheckBoxPanel(), BorderLayout.NORTH);
+ mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ private Component buildCheckBoxPanel() {
+ JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+ taskListPanel.add(this.buildFlag1CheckBox());
+ taskListPanel.add(this.buildFlag2CheckBox());
+ taskListPanel.add(this.buildNotFlag2CheckBox());
+ taskListPanel.add(this.buildUnattachedCheckBox());
+ return taskListPanel;
+ }
+
+ private JCheckBox buildFlag1CheckBox() {
+ JCheckBox checkBox = new JCheckBox();
+ checkBox.setText("flag 1");
+ checkBox.setModel(this.flag1ButtonModel);
+ return checkBox;
+ }
+
+ private JCheckBox buildFlag2CheckBox() {
+ JCheckBox checkBox = new JCheckBox();
+ checkBox.setText("flag 2");
+ checkBox.setModel(this.flag2ButtonModel);
+ return checkBox;
+ }
+
+ private JCheckBox buildNotFlag2CheckBox() {
+ JCheckBox checkBox = new JCheckBox();
+ checkBox.setText("not flag 2");
+ checkBox.setModel(this.notFlag2ButtonModel);
+ return checkBox;
+ }
+
+ private JCheckBox buildUnattachedCheckBox() {
+ JCheckBox checkBox = new JCheckBox("unattached");
+ checkBox.getModel().addItemListener(this.buildUnattachedItemListener());
+ return checkBox;
+ }
+
+ private ItemListener buildUnattachedItemListener() {
+ return new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ System.out.println("unattached state changed: " + e);
+ }
+ };
+ }
+
+ private Component buildControlPanel() {
+ JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+ controlPanel.add(this.buildFlipFlag1Button());
+ controlPanel.add(this.buildClearModelButton());
+ controlPanel.add(this.buildRestoreModelButton());
+ controlPanel.add(this.buildPrintModelButton());
+ return controlPanel;
+ }
+
+ private JButton buildFlipFlag1Button() {
+ return new JButton(this.buildFlipFlag1Action());
+ }
+
+ private Action buildFlipFlag1Action() {
+ Action action = new AbstractAction("flip flag 1") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ CheckBoxModelAdapterUITest.this.flipFlag1();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void flipFlag1() {
+ this.testModel.setFlag1( ! this.testModel.isFlag1());
+ }
+
+ private JButton buildClearModelButton() {
+ return new JButton(this.buildClearModelAction());
+ }
+
+ private Action buildClearModelAction() {
+ Action action = new AbstractAction("clear model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ CheckBoxModelAdapterUITest.this.clearModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void clearModel() {
+ this.testModelHolder.setValue(null);
+ }
+
+ private JButton buildRestoreModelButton() {
+ return new JButton(this.buildRestoreModelAction());
+ }
+
+ private Action buildRestoreModelAction() {
+ Action action = new AbstractAction("restore model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ CheckBoxModelAdapterUITest.this.restoreModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void restoreModel() {
+ this.testModelHolder.setValue(this.testModel);
+ }
+
+ private JButton buildPrintModelButton() {
+ return new JButton(this.buildPrintModelAction());
+ }
+
+ private Action buildPrintModelAction() {
+ Action action = new AbstractAction("print model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ CheckBoxModelAdapterUITest.this.printModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void printModel() {
+ System.out.println("flag 1: " + this.testModel.isFlag1());
+ System.out.println("flag 2: " + this.testModel.isFlag2());
+ System.out.println("not flag 2: " + this.testModel.isNotFlag2());
+ System.out.println("***");
+ }
+
+
+ private class TestModel extends AbstractModel {
+ private boolean flag1;
+ public static final String FLAG1_PROPERTY = "flag1";
+ private boolean flag2;
+ public static final String FLAG2_PROPERTY = "flag2";
+ private boolean notFlag2;
+ public static final String NOT_FLAG2_PROPERTY = "notFlag2";
+
+ public TestModel(boolean flag1, boolean flag2) {
+ this.flag1 = flag1;
+ this.flag2 = flag2;
+ this.notFlag2 = ! flag2;
+ }
+ public boolean isFlag1() {
+ return this.flag1;
+ }
+ public void setFlag1(boolean flag1) {
+ boolean old = this.flag1;
+ this.flag1 = flag1;
+ this.firePropertyChanged(FLAG1_PROPERTY, old, flag1);
+ }
+ public boolean isFlag2() {
+ return this.flag2;
+ }
+ public void setFlag2(boolean flag2) {
+ boolean old = this.flag2;
+ this.flag2 = flag2;
+ this.firePropertyChanged(FLAG2_PROPERTY, old, flag2);
+
+ old = this.notFlag2;
+ this.notFlag2 = ! flag2;
+ this.firePropertyChanged(NOT_FLAG2_PROPERTY, old, this.notFlag2);
+ }
+ public boolean isNotFlag2() {
+ return this.notFlag2;
+ }
+ public void setNotFlag2(boolean notFlag2) {
+ this.setFlag2( ! notFlag2);
+ }
+ @Override
+ public String toString() {
+ return "TestModel(" + this.isFlag1() + " - " + this.isFlag2() + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterTests.java
new file mode 100644
index 0000000..65e3bf1
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterTests.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.ComboBoxModel;
+import javax.swing.ListModel;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ComboBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+import org.eclipse.persistence.tools.utility.tests.model.SimpleDisplayable;
+import org.eclipse.persistence.tools.utility.tests.model.value.CoordinatedList;
+
+@SuppressWarnings("nls")
+public class ComboBoxModelAdapterTests extends TestCase {
+
+ public ComboBoxModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // nothing yet...
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ // nothing yet...
+ super.tearDown();
+ }
+
+ public void testHasListeners() throws Exception {
+ SimpleListValueModel<Displayable> listHolder = this.buildListHolder();
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ SimplePropertyValueModel<Object> selectionHolder = new SimplePropertyValueModel<Object>(listHolder.iterator().next());
+ assertFalse(selectionHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ ComboBoxModel comboBoxModel = new ComboBoxModelAdapter(listHolder, selectionHolder);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(selectionHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(comboBoxModel);
+
+ CoordinatedList<Displayable> synchList = new CoordinatedList<Displayable>(comboBoxModel);
+ PropertyChangeListener selectionListener = this.buildSelectionListener();
+ selectionHolder.addPropertyChangeListener(PropertyValueModel.VALUE, selectionListener);
+ assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(selectionHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasListeners(comboBoxModel);
+
+ comboBoxModel.removeListDataListener(synchList);
+ selectionHolder.removePropertyChangeListener(PropertyValueModel.VALUE, selectionListener);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertFalse(selectionHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(comboBoxModel);
+ }
+
+ private PropertyChangeListener buildSelectionListener() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent evt) {
+ // do nothing...
+ }
+ };
+ }
+
+ private void verifyHasNoListeners(ListModel listModel) throws Exception {
+ boolean hasNoListeners = ((Boolean) ObjectTools.execute(listModel, "hasNoListDataListeners")).booleanValue();
+ assertTrue(hasNoListeners);
+ }
+
+ private void verifyHasListeners(ListModel listModel) throws Exception {
+ boolean hasListeners = ((Boolean) ObjectTools.execute(listModel, "hasListDataListeners")).booleanValue();
+ assertTrue(hasListeners);
+ }
+
+ private SimpleListValueModel<Displayable> buildListHolder() {
+ return new SimpleListValueModel<Displayable>(this.buildList());
+ }
+
+ private List<Displayable> buildList() {
+ List<Displayable> list = new ArrayList<Displayable>();
+ this.populateCollection(list);
+ return list;
+ }
+
+ private void populateCollection(Collection<Displayable> c) {
+ c.add(new SimpleDisplayable("foo"));
+ c.add(new SimpleDisplayable("bar"));
+ c.add(new SimpleDisplayable("baz"));
+ c.add(new SimpleDisplayable("joo"));
+ c.add(new SimpleDisplayable("jar"));
+ c.add(new SimpleDisplayable("jaz"));
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest.java
new file mode 100644
index 0000000..a601008
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest.java
@@ -0,0 +1,400 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.ListCellRenderer;
+import javax.swing.UIManager;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ComboBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.swing.FilteringListBrowser;
+import org.eclipse.persistence.tools.utility.swing.ListChooser;
+import org.eclipse.persistence.tools.utility.swing.SimpleListCellRenderer;
+
+
+/**
+ * Play around with a set of combo-boxes.
+ *
+ * DefaultLongListBrowserDialogUITest subclasses this class; so be
+ * careful when making changes.
+ */
+@SuppressWarnings("nls")
+public class ComboBoxModelAdapterUITest {
+
+ protected JFrame window;
+ private TestModel testModel;
+ private ModifiablePropertyValueModel<TestModel> testModelHolder;
+ private ModifiablePropertyValueModel<Object> colorHolder;
+ private SimpleListValueModel<String> colorListHolder;
+ protected ComboBoxModel colorComboBoxModel;
+ private int nextColorNumber = 0;
+
+ public static void main(String[] args) throws Exception {
+ new ComboBoxModelAdapterUITest().exec();
+ }
+
+ protected ComboBoxModelAdapterUITest() {
+ super();
+ }
+
+ protected void exec() throws Exception {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); // Metal LAF
+// UIManager.setLookAndFeel(com.sun.java.swing.plaf.windows.WindowsLookAndFeel.class.getName());
+// UIManager.setLookAndFeel(com.sun.java.swing.plaf.motif.MotifLookAndFeel.class.getName());
+// UIManager.setLookAndFeel(oracle.bali.ewt.olaf.OracleLookAndFeel.class.getName());
+ this.testModel = this.buildTestModel();
+ this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+ this.colorHolder = this.buildColorHolder(this.testModelHolder);
+ this.colorListHolder = this.buildColorListHolder();
+ this.colorComboBoxModel = this.buildComboBoxModelAdapter(this.colorListHolder, this.colorHolder);
+ this.openWindow();
+ }
+
+ private ModifiablePropertyValueModel<Object> buildColorHolder(PropertyValueModel<TestModel> vm) {
+ return new PropertyAspectAdapter<TestModel, Object>(vm, TestModel.COLOR_PROPERTY) {
+ @Override
+ protected String buildValue_() {
+ return this.subject.getColor();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setColor((String) value);
+ }
+ };
+ }
+
+ protected TestModel buildTestModel() {
+ return new TestModel();
+ }
+
+ private SimpleListValueModel<String> buildColorListHolder() {
+ return new SimpleListValueModel<String>(TestModel.validColors());
+// return new AbstractReadOnlyListValueModel() {
+// public Object value() {
+// return new ArrayListIterator(TestModel.VALID_COLORS);
+// }
+// public int size() {
+// return TestModel.VALID_COLORS.length;
+// }
+// };
+ }
+
+ protected ListValueModel<String> uiColorListHolder() {
+ return this.colorListHolder;
+ }
+
+ private ComboBoxModel buildComboBoxModelAdapter(ListValueModel<String> listHolder, ModifiablePropertyValueModel<Object> selectionHolder) {
+ return new ComboBoxModelAdapter(listHolder, selectionHolder);
+ }
+
+ private void openWindow() {
+ this.window = new JFrame(this.getClass().getSimpleName());
+ this.window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ this.window.addWindowListener(this.buildWindowListener());
+ this.window.getContentPane().add(this.buildMainPanel(), "Center");
+ this.window.setLocation(300, 300);
+ this.window.setSize(400, 150);
+ this.window.setVisible(true);
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private Component buildMainPanel() {
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(this.buildComboBoxPanel(), BorderLayout.NORTH);
+ mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ protected JPanel buildComboBoxPanel() {
+ JPanel panel = new JPanel(new GridLayout(1, 0));
+ panel.add(this.buildComboBox());
+ panel.add(this.buildComboBox());
+ panel.add(this.buildListChooser1());
+ panel.add(this.buildListChooser2());
+ return panel;
+ }
+
+ private JComboBox buildComboBox() {
+ JComboBox comboBox = new JComboBox(this.colorComboBoxModel);
+ comboBox.setRenderer(this.buildComboBoxRenderer());
+ return comboBox;
+ }
+
+ protected ListCellRenderer buildComboBoxRenderer() {
+ return new SimpleListCellRenderer() {
+ @Override
+ protected String buildText(Object value) {
+ return super.buildText(value);
+ }
+ };
+ }
+
+ private ListChooser buildListChooser1() {
+ return new LocalListChooser1(this.colorComboBoxModel);
+ }
+
+ private ListChooser buildListChooser2() {
+ return new LocalListChooser2(this.colorComboBoxModel);
+ }
+
+ private Component buildControlPanel() {
+ JPanel controlPanel = new JPanel(new GridLayout(2, 0));
+ controlPanel.add(this.buildResetColorButton());
+ controlPanel.add(this.buildClearModelButton());
+ controlPanel.add(this.buildRestoreModelButton());
+ controlPanel.add(this.buildPrintModelButton());
+ controlPanel.add(this.buildAddTenButton());
+ controlPanel.add(this.buildRemoveTenButton());
+ return controlPanel;
+ }
+
+ // ********** reset color button **********
+ private JButton buildResetColorButton() {
+ return new JButton(this.buildResetColorAction());
+ }
+
+ private Action buildResetColorAction() {
+ Action action = new AbstractAction("reset color") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ComboBoxModelAdapterUITest.this.resetColor();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void resetColor() {
+ this.testModel.setColor(TestModel.DEFAULT_COLOR);
+ }
+
+ // ********** clear model button **********
+ private JButton buildClearModelButton() {
+ return new JButton(this.buildClearModelAction());
+ }
+
+ private Action buildClearModelAction() {
+ Action action = new AbstractAction("clear model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ComboBoxModelAdapterUITest.this.clearModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void clearModel() {
+ this.testModelHolder.setValue(null);
+ }
+
+ // ********** restore model button **********
+ private JButton buildRestoreModelButton() {
+ return new JButton(this.buildRestoreModelAction());
+ }
+
+ private Action buildRestoreModelAction() {
+ Action action = new AbstractAction("restore model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ComboBoxModelAdapterUITest.this.restoreModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void restoreModel() {
+ this.testModelHolder.setValue(this.testModel);
+ }
+
+ // ********** print model button **********
+ private JButton buildPrintModelButton() {
+ return new JButton(this.buildPrintModelAction());
+ }
+
+ private Action buildPrintModelAction() {
+ Action action = new AbstractAction("print model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ComboBoxModelAdapterUITest.this.printModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void printModel() {
+ System.out.println(this.testModel);
+ }
+
+ // ********** add 20 button **********
+ private JButton buildAddTenButton() {
+ return new JButton(this.buildAddTenAction());
+ }
+
+ private Action buildAddTenAction() {
+ Action action = new AbstractAction("add 20") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ComboBoxModelAdapterUITest.this.addTen();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void addTen() {
+ for (int i = this.nextColorNumber; i < this.nextColorNumber + 20; i++) {
+ this.colorListHolder.add(this.colorListHolder.size(), "color" + i);
+ }
+ this.nextColorNumber += 20;
+ }
+
+ // ********** remove 20 button **********
+ private JButton buildRemoveTenButton() {
+ return new JButton(this.buildRemoveTenAction());
+ }
+
+ private Action buildRemoveTenAction() {
+ Action action = new AbstractAction("remove 20") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ComboBoxModelAdapterUITest.this.removeTen();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void removeTen() {
+ for (int i = 0; i < 20; i++) {
+ if (this.colorListHolder.size() > 0) {
+ this.colorListHolder.remove(this.colorListHolder.size() - 1);
+ }
+ }
+ }
+
+
+ protected static class TestModel extends AbstractModel {
+ private String color;
+ public static final String COLOR_PROPERTY = "color";
+ public static final String RED = "red";
+ public static final String ORANGE = "orange";
+ public static final String YELLOW = "yellow";
+ public static final String GREEN = "green";
+ public static final String BLUE = "blue";
+ public static final String INDIGO = "indigo";
+ public static final String VIOLET = "violet";
+ public static final String DEFAULT_COLOR = RED;
+ public static List<String> validColors;
+ public static final String[] DEFAULT_VALID_COLORS = {
+ RED,
+ ORANGE,
+ YELLOW,
+ GREEN,
+ BLUE,
+ INDIGO,
+ VIOLET
+ };
+
+ public static List<String> validColors() {
+ if (validColors == null) {
+ validColors = buildDefaultValidColors();
+ }
+ return validColors;
+ }
+ public static List<String> buildDefaultValidColors() {
+ List<String> result = new ArrayList<String>();
+ CollectionTools.addAll(result, DEFAULT_VALID_COLORS);
+ return result;
+ }
+
+ public TestModel() {
+ this(DEFAULT_COLOR);
+ }
+ public TestModel(String color) {
+ this.color = color;
+ }
+ public String getColor() {
+ return this.color;
+ }
+ public void setColor(String color) {
+ this.checkColor(color);
+ Object old = this.color;
+ this.color = color;
+ this.firePropertyChanged(COLOR_PROPERTY, old, color);
+ }
+ public void checkColor(String c) {
+ if ( ! validColors().contains(c)) {
+ throw new IllegalArgumentException(c);
+ }
+ }
+ @Override
+ public String toString() {
+ return "TestModel(" + this.color + ")";
+ }
+ }
+
+
+ private class LocalListChooser1 extends ListChooser {
+ public LocalListChooser1(ComboBoxModel model) {
+ super(model);
+ }
+ }
+
+
+ private class LocalListChooser2 extends ListChooser {
+ public LocalListChooser2(ComboBoxModel model) {
+ super(model);
+ }
+ @Override
+ protected ListBrowser buildBrowser() {
+ return new FilteringListBrowser<String>();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest2.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest2.java
new file mode 100644
index 0000000..89b29fb
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest2.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.ListCellRenderer;
+import org.eclipse.persistence.tools.utility.model.value.ExtendedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.swing.SimpleListCellRenderer;
+
+@SuppressWarnings("nls")
+public class ComboBoxModelAdapterUITest2 extends ComboBoxModelAdapterUITest {
+
+ public static void main(String[] args) throws Exception {
+ new ComboBoxModelAdapterUITest2().exec();
+ }
+
+ public ComboBoxModelAdapterUITest2() {
+ super();
+ }
+
+ /**
+ * use a different model that allows the color to be set to null
+ */
+ @Override
+ protected TestModel buildTestModel() {
+ return new TestModel2();
+ }
+
+ /**
+ * add a null to the front of the list
+ */
+ @Override
+ protected ListValueModel<String> uiColorListHolder() {
+ // the default is to prepend the wrapped list with a null item
+ return new ExtendedListValueModelWrapper<String>(super.uiColorListHolder());
+ }
+
+ /**
+ * convert null to some text
+ */
+ @Override
+ protected ListCellRenderer buildComboBoxRenderer() {
+ return new SimpleListCellRenderer() {
+ @Override
+ protected String buildText(Object value) {
+ return (value == null) ? "<none selected>" : super.buildText(value);
+ }
+ };
+ }
+
+
+ protected static class TestModel2 extends TestModel {
+ /**
+ * null is OK here
+ */
+ @Override
+ public void checkColor(String color) {
+ if (color == null) {
+ return;
+ }
+ super.checkColor(color);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DateSpinnerModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DateSpinnerModelAdapterTests.java
new file mode 100644
index 0000000..3c5f408
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DateSpinnerModelAdapterTests.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.util.Date;
+import javax.swing.SpinnerModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.DateSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class DateSpinnerModelAdapterTests extends TestCase {
+ private ModifiablePropertyValueModel<Object> valueHolder;
+ private SpinnerModel spinnerModelAdapter;
+ boolean eventFired;
+
+ public DateSpinnerModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.valueHolder = new SimplePropertyValueModel<Object>(new Date());
+ this.spinnerModelAdapter = new DateSpinnerModelAdapter(this.valueHolder) {
+ @Override
+ protected PropertyChangeListener buildDateChangeListener() {
+ return this.buildDateChangeListener_();
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testSetValueSpinnerModel() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ DateSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ Date newDate = new Date();
+ newDate.setTime(777777);
+ this.spinnerModelAdapter.setValue(newDate);
+ assertTrue(this.eventFired);
+ assertEquals(777777, ((Date) this.valueHolder.getValue()).getTime());
+ }
+
+ public void testSetValueValueHolder() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ DateSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ Date newDate = new Date();
+ newDate.setTime(777777);
+ this.valueHolder.setValue(newDate);
+ assertTrue(this.eventFired);
+ assertEquals(777777, ((Date) this.spinnerModelAdapter.getValue()).getTime());
+ }
+
+ public void testDefaultValue() throws Exception {
+ Date newDate = new Date();
+ newDate.setTime(777777);
+ this.valueHolder.setValue(newDate);
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ DateSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertEquals(777777, ((Date) this.spinnerModelAdapter.getValue()).getTime());
+ this.valueHolder.setValue(null);
+ assertTrue(this.eventFired);
+ assertFalse(((Date) this.spinnerModelAdapter.getValue()).getTime() == 777777);
+ }
+
+ public void testHasListeners() throws Exception {
+ SimplePropertyValueModel<Object> localValueHolder = (SimplePropertyValueModel<Object>) this.valueHolder;
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.spinnerModelAdapter);
+
+ ChangeListener listener = new TestChangeListener();
+ this.spinnerModelAdapter.addChangeListener(listener);
+ assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasListeners(this.spinnerModelAdapter);
+
+ this.spinnerModelAdapter.removeChangeListener(listener);
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.spinnerModelAdapter);
+ }
+
+ private void verifyHasNoListeners(SpinnerModel adapter) throws Exception {
+ assertEquals(0, ((DateSpinnerModelAdapter) adapter).getChangeListeners().length);
+ }
+
+ private void verifyHasListeners(Object adapter) throws Exception {
+ assertFalse(((DateSpinnerModelAdapter) adapter).getChangeListeners().length == 0);
+ }
+
+ public void testNullInitialValue() {
+ Date today = new Date();
+ this.valueHolder = new SimplePropertyValueModel<Object>();
+ this.spinnerModelAdapter = new DateSpinnerModelAdapter(this.valueHolder, today) {
+ @Override
+ protected PropertyChangeListener buildDateChangeListener() {
+ return this.buildDateChangeListener_();
+ }
+ };
+
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ DateSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertEquals(today, this.spinnerModelAdapter.getValue());
+
+ Date newDate = new Date();
+ newDate.setTime(777777);
+ this.valueHolder.setValue(newDate);
+
+ assertTrue(this.eventFired);
+ assertEquals(777777, ((Date) this.spinnerModelAdapter.getValue()).getTime());
+ }
+
+
+ // ********** inner class **********
+ private class TestChangeListener implements ChangeListener {
+ TestChangeListener() {
+ super();
+ }
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterTests.java
new file mode 100644
index 0000000..8b51181
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterTests.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentEvent.EventType;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.Document;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.DocumentAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class DocumentAdapterTests extends TestCase {
+ private ModifiablePropertyValueModel<String> stringHolder;
+ Document documentAdapter;
+ boolean eventFired;
+
+ public DocumentAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.stringHolder = new SimplePropertyValueModel<String>("0123456789");
+ this.documentAdapter = new DocumentAdapter(this.stringHolder) {
+ @Override
+ protected PropertyChangeListener buildStringListener() {
+ return this.buildStringListener_();
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testRemove() throws Exception {
+ this.eventFired = false;
+ this.documentAdapter.addDocumentListener(new TestDocumentListener() {
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ DocumentAdapterTests.this.eventFired = true;
+ assertEquals(EventType.REMOVE, e.getType());
+ assertEquals(DocumentAdapterTests.this.documentAdapter, e.getDocument());
+ // this will be the removal of "23456"
+ assertEquals(2, e.getOffset());
+ assertEquals(5, e.getLength());
+ }
+ });
+ this.documentAdapter.remove(2, 5);
+ assertTrue(this.eventFired);
+ assertEquals("01789", this.stringHolder.getValue());
+ }
+
+ public void testInsert() throws Exception {
+ this.eventFired = false;
+ this.documentAdapter.addDocumentListener(new TestDocumentListener() {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ DocumentAdapterTests.this.eventFired = true;
+ assertEquals(EventType.INSERT, e.getType());
+ assertEquals(DocumentAdapterTests.this.documentAdapter, e.getDocument());
+ // this will be the insert of "xxxxxx"
+ assertEquals(2, e.getOffset());
+ assertEquals(5, e.getLength());
+ }
+ });
+ this.documentAdapter.insertString(2, "xxxxx", null);
+ assertTrue(this.eventFired);
+ assertEquals("01xxxxx23456789", this.stringHolder.getValue());
+ }
+
+ public void testSetValue() throws Exception {
+ this.eventFired = false;
+ this.documentAdapter.addDocumentListener(new TestDocumentListener() {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ DocumentAdapterTests.this.eventFired = true;
+ assertEquals(EventType.INSERT, e.getType());
+ assertEquals(DocumentAdapterTests.this.documentAdapter, e.getDocument());
+ // this will be the insert of "foo"
+ assertEquals(0, e.getOffset());
+ assertEquals(3, e.getLength());
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ assertEquals(EventType.REMOVE, e.getType());
+ assertEquals(DocumentAdapterTests.this.documentAdapter, e.getDocument());
+ // this will be the removal of "0123456789"
+ assertEquals(0, e.getOffset());
+ assertEquals(10, e.getLength());
+ }
+ });
+ assertEquals("0123456789", this.documentAdapter.getText(0, this.documentAdapter.getLength()));
+ this.stringHolder.setValue("foo");
+ assertTrue(this.eventFired);
+ assertEquals("foo", this.documentAdapter.getText(0, this.documentAdapter.getLength()));
+ }
+
+ public void testHasListeners() throws Exception {
+ SimplePropertyValueModel<String> localStringHolder = (SimplePropertyValueModel<String>) this.stringHolder;
+ assertFalse(localStringHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.documentAdapter);
+
+ DocumentListener listener = new TestDocumentListener();
+ this.documentAdapter.addDocumentListener(listener);
+ assertTrue(localStringHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasListeners(this.documentAdapter);
+
+ this.documentAdapter.removeDocumentListener(listener);
+ assertFalse(localStringHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.documentAdapter);
+ }
+
+ private void verifyHasNoListeners(Object document) throws Exception {
+ Object delegate = ObjectTools.get(document, "delegate");
+ Object[] listeners = (Object[]) ObjectTools.execute(delegate, "getDocumentListeners");
+ assertEquals(0, listeners.length);
+ }
+
+ private void verifyHasListeners(Object document) throws Exception {
+ Object delegate = ObjectTools.get(document, "delegate");
+ Object[] listeners = (Object[]) ObjectTools.execute(delegate, "getDocumentListeners");
+ assertFalse(listeners.length == 0);
+ }
+
+
+ private class TestDocumentListener implements DocumentListener {
+ TestDocumentListener() {
+ super();
+ }
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterUITest.java
new file mode 100644
index 0000000..4c3b74e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterUITest.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.WindowConstants;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.PlainDocument;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.DocumentAdapter;
+
+/**
+ * Play around with a set of entry fields.
+ */
+@SuppressWarnings("nls")
+public class DocumentAdapterUITest {
+
+ private TestModel testModel;
+ private static final String DEFAULT_NAME = "Scooby Doo";
+ private ModifiablePropertyValueModel<TestModel> testModelHolder;
+ private ModifiablePropertyValueModel<String> nameHolder;
+ private Document nameDocument;
+ private Document upperCaseNameDocument;
+
+ public static void main(String[] args) throws Exception {
+ new DocumentAdapterUITest().exec();
+ }
+
+ private DocumentAdapterUITest() {
+ super();
+ }
+
+ private void exec() throws Exception {
+ this.testModel = new TestModel(DEFAULT_NAME);
+ this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+ this.nameHolder = this.buildNameHolder(this.testModelHolder);
+ this.nameDocument = this.buildNameDocument(this.nameHolder);
+ this.upperCaseNameDocument = this.buildUpperCaseNameDocument(this.nameHolder);
+ this.openWindow();
+ }
+
+ private ModifiablePropertyValueModel<String> buildNameHolder(PropertyValueModel<TestModel> vm) {
+ return new PropertyAspectAdapter<TestModel, String>(vm, TestModel.NAME_PROPERTY) {
+ @Override
+ protected String buildValue_() {
+ return this.subject.getName();
+ }
+ @Override
+ protected void setValue_(String value) {
+ this.subject.setName(value);
+ }
+ };
+ }
+
+ private Document buildNameDocument(ModifiablePropertyValueModel<String> stringHolder) {
+ return new DocumentAdapter(stringHolder);
+ }
+
+ private Document buildUpperCaseNameDocument(ModifiablePropertyValueModel<String> stringHolder) {
+ return new DocumentAdapter(stringHolder, this.buildUpperCaseNameDocumentDelegate());
+ }
+
+ private AbstractDocument buildUpperCaseNameDocumentDelegate() {
+ return new PlainDocument() {
+ @Override
+ public void insertString(int offset, String string, AttributeSet a) throws BadLocationException {
+ if (string == null) {
+ return;
+ }
+ char[] upper = string.toCharArray();
+ for (int i = 0; i < upper.length; i++) {
+ upper[i] = Character.toUpperCase(upper[i]);
+ }
+ super.insertString(offset, new String(upper), a);
+ }
+ };
+ }
+
+ private void openWindow() {
+ JFrame window = new JFrame(this.getClass().getName());
+ window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ window.addWindowListener(this.buildWindowListener());
+ window.getContentPane().add(this.buildMainPanel(), "Center");
+ window.setSize(400, 100);
+ window.setVisible(true);
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private Component buildMainPanel() {
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(this.buildTextFieldPanel(), BorderLayout.NORTH);
+ mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ private Component buildTextFieldPanel() {
+ JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+ taskListPanel.add(this.buildNameTextField());
+ taskListPanel.add(this.buildReadOnlyNameTextField());
+ taskListPanel.add(this.buildUpperCaseNameTextField());
+ return taskListPanel;
+ }
+
+ private JTextField buildNameTextField() {
+ return new JTextField(this.nameDocument, null, 0);
+ }
+
+ private JTextField buildReadOnlyNameTextField() {
+ JTextField nameTextField = this.buildNameTextField();
+ nameTextField.setEditable(false);
+ return nameTextField;
+ }
+
+ private JTextField buildUpperCaseNameTextField() {
+ return new JTextField(this.upperCaseNameDocument, null, 0);
+ }
+
+ private Component buildControlPanel() {
+ JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+ controlPanel.add(this.buildResetNameButton());
+ controlPanel.add(this.buildClearModelButton());
+ controlPanel.add(this.buildRestoreModelButton());
+ controlPanel.add(this.buildPrintModelButton());
+ return controlPanel;
+ }
+
+ private JButton buildResetNameButton() {
+ return new JButton(this.buildResetNameAction());
+ }
+
+ private Action buildResetNameAction() {
+ Action action = new AbstractAction("reset name") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ DocumentAdapterUITest.this.resetName();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void resetName() {
+ this.testModel.setName(DEFAULT_NAME);
+ }
+
+ private JButton buildClearModelButton() {
+ return new JButton(this.buildClearModelAction());
+ }
+
+ private Action buildClearModelAction() {
+ Action action = new AbstractAction("clear model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ DocumentAdapterUITest.this.clearModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void clearModel() {
+ this.testModelHolder.setValue(null);
+ }
+
+ private JButton buildRestoreModelButton() {
+ return new JButton(this.buildRestoreModelAction());
+ }
+
+ private Action buildRestoreModelAction() {
+ Action action = new AbstractAction("restore model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ DocumentAdapterUITest.this.restoreModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void restoreModel() {
+ this.testModelHolder.setValue(this.testModel);
+ }
+
+ private JButton buildPrintModelButton() {
+ return new JButton(this.buildPrintModelAction());
+ }
+
+ private Action buildPrintModelAction() {
+ Action action = new AbstractAction("print model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ DocumentAdapterUITest.this.printModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void printModel() {
+ System.out.println("name: " + this.testModel.getName());
+ }
+
+
+ private class TestModel extends AbstractModel {
+ private String name;
+ public static final String NAME_PROPERTY = "name";
+
+ public TestModel(String name) {
+ this.name = name;
+ }
+ public String getName() {
+ return this.name;
+ }
+ public void setName(String name) {
+ Object old = this.name;
+ this.name = name;
+ this.firePropertyChanged(NAME_PROPERTY, old, name);
+ }
+ @Override
+ public String toString() {
+ return "TestModel(" + this.getName() + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterTests.java
new file mode 100644
index 0000000..ad6728e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterTests.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.swing.ListModel;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.value.CoordinatedList;
+
+@SuppressWarnings("nls")
+public class ListModelAdapterTests extends TestCase {
+
+ public ListModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // nothing yet...
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ // nothing yet...
+ super.tearDown();
+ }
+
+ private ListModelAdapter buildListModel(ListValueModel<String> listHolder) {
+ return new ListModelAdapter(listHolder) {
+ @Override
+ protected ListChangeListener buildListChangeListener() {
+ return this.buildListChangeListener_();
+ }
+ };
+ }
+
+ private ListModel buildListModel(CollectionValueModel<String> collectionHolder) {
+ return new ListModelAdapter(collectionHolder) {
+ @Override
+ protected ListChangeListener buildListChangeListener() {
+ return this.buildListChangeListener_();
+ }
+ };
+ }
+
+ public void testCollectionSynchronization() {
+ SimpleCollectionValueModel<String> collectionHolder = this.buildCollectionHolder();
+ ListModel listModel = this.buildListModel(collectionHolder);
+ CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+ assertEquals(6, synchList.size());
+ this.compare(listModel, synchList);
+
+ collectionHolder.add("tom");
+ collectionHolder.add("dick");
+ collectionHolder.add("harry");
+ collectionHolder.add(null);
+ assertEquals(10, synchList.size());
+ this.compare(listModel, synchList);
+
+ collectionHolder.remove("foo");
+ collectionHolder.remove("jar");
+ collectionHolder.remove("harry");
+ collectionHolder.remove(null);
+ assertEquals(6, synchList.size());
+ this.compare(listModel, synchList);
+ }
+
+ public void testListSynchronization() {
+ SimpleListValueModel<String> listHolder = this.buildListHolder();
+ ListModel listModel = this.buildListModel(listHolder);
+ CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+ assertEquals(6, synchList.size());
+ this.compare(listModel, synchList);
+
+ listHolder.add(6, "tom");
+ listHolder.add(7, "dick");
+ listHolder.add(8, "harry");
+ listHolder.add(9, null);
+ assertEquals(10, synchList.size());
+ this.compare(listModel, synchList);
+
+ listHolder.remove(9);
+ listHolder.remove(8);
+ listHolder.remove(4);
+ listHolder.remove(0);
+ assertEquals(6, synchList.size());
+ this.compare(listModel, synchList);
+ }
+
+ public void testSetModel() {
+ SimpleListValueModel<String> listHolder1 = this.buildListHolder();
+ ListModelAdapter listModel = this.buildListModel(listHolder1);
+ CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+ assertTrue(listHolder1.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ assertEquals(6, synchList.size());
+ this.compare(listModel, synchList);
+
+ SimpleListValueModel<String> listHolder2 = this.buildListHolder2();
+ listModel.setModel(listHolder2);
+ assertEquals(3, synchList.size());
+ this.compare(listModel, synchList);
+ assertTrue(listHolder1.hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(listHolder2.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ listModel.setModel(new SimpleListValueModel<String>());
+ assertEquals(0, synchList.size());
+ this.compare(listModel, synchList);
+ assertTrue(listHolder1.hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+ assertTrue(listHolder2.hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ private void compare(ListModel listModel, List<String> list) {
+ assertEquals(listModel.getSize(), list.size());
+ for (int i = 0; i < listModel.getSize(); i++) {
+ assertEquals(listModel.getElementAt(i), list.get(i));
+ }
+ }
+
+ public void testCollectionSort() {
+ this.verifyCollectionSort(null);
+ }
+
+ public void testListSort() {
+ this.verifyListSort(null);
+ }
+
+ public void testCustomCollectionSort() {
+ this.verifyCollectionSort(this.buildCustomComparator());
+ }
+
+ public void testCustomListSort() {
+ this.verifyListSort(this.buildCustomComparator());
+ }
+
+ private Comparator<String> buildCustomComparator() {
+ // sort with reverse order
+ return new Comparator<String>() {
+ @Override
+ public int compare(String s1, String s2) {
+ return s2.compareTo(s1);
+ }
+ };
+ }
+
+ private void verifyCollectionSort(Comparator<String> comparator) {
+ SimpleCollectionValueModel<String> collectionHolder = this.buildCollectionHolder();
+ ListModel listModel = this.buildListModel(new SortedListValueModelAdapter<String>(collectionHolder, comparator));
+ CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+ assertEquals(6, synchList.size());
+ this.compareSort(listModel, synchList, comparator);
+
+ collectionHolder.add("tom");
+ collectionHolder.add("dick");
+ collectionHolder.add("harry");
+ assertEquals(9, synchList.size());
+ this.compareSort(listModel, synchList, comparator);
+
+ collectionHolder.remove("foo");
+ collectionHolder.remove("jar");
+ collectionHolder.remove("harry");
+ assertEquals(6, synchList.size());
+ this.compareSort(listModel, synchList, comparator);
+ }
+
+ private void verifyListSort(Comparator<String> comparator) {
+ SimpleListValueModel<String> listHolder = this.buildListHolder();
+ ListModel listModel = this.buildListModel(new SortedListValueModelWrapper<String>(listHolder, comparator));
+ CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+ assertEquals(6, synchList.size());
+ this.compareSort(listModel, synchList, comparator);
+
+ listHolder.add(0, "tom");
+ listHolder.add(0, "dick");
+ listHolder.add(0, "harry");
+ assertEquals(9, synchList.size());
+ this.compareSort(listModel, synchList, comparator);
+
+ listHolder.remove(8);
+ listHolder.remove(4);
+ listHolder.remove(0);
+ listHolder.remove(5);
+ assertEquals(5, synchList.size());
+ this.compareSort(listModel, synchList, comparator);
+ }
+
+ private void compareSort(ListModel listModel, List<String> list, Comparator<String> comparator) {
+ SortedSet<String> ss = new TreeSet<String>(comparator);
+ for (int i = 0; i < listModel.getSize(); i++) {
+ ss.add((String) listModel.getElementAt(i));
+ }
+ assertEquals(ss.size(), list.size());
+ for (Iterator<String> stream1 = ss.iterator(), stream2 = list.iterator(); stream1.hasNext(); ) {
+ assertEquals(stream1.next(), stream2.next());
+ }
+ }
+
+ public void testHasListeners() throws Exception {
+ SimpleListValueModel<String> listHolder = this.buildListHolder();
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ ListModel listModel = this.buildListModel(listHolder);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.verifyHasNoListeners(listModel);
+
+ CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+ assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.verifyHasListeners(listModel);
+
+ listModel.removeListDataListener(synchList);
+ assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ this.verifyHasNoListeners(listModel);
+ }
+
+ public void testGetSize() throws Exception {
+ SimpleListValueModel<String> listHolder = this.buildListHolder();
+ ListModel listModel = this.buildListModel(listHolder);
+ this.verifyHasNoListeners(listModel);
+ assertEquals(6, listModel.getSize());
+
+ CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+ this.verifyHasListeners(listModel);
+ assertEquals(6, listModel.getSize());
+
+ listModel.removeListDataListener(synchList);
+ this.verifyHasNoListeners(listModel);
+ assertEquals(6, listModel.getSize());
+ }
+
+ public void testGetElementAt() throws Exception {
+ SimpleListValueModel<String> listHolder = this.buildListHolder();
+ ListModel listModel = this.buildListModel(new SortedListValueModelWrapper<String>(listHolder));
+ CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+ this.verifyHasListeners(listModel);
+ assertEquals("bar", listModel.getElementAt(0));
+ assertEquals("bar", synchList.get(0));
+ }
+
+ private void verifyHasNoListeners(ListModel listModel) throws Exception {
+ boolean hasNoListeners = ((Boolean) ObjectTools.execute(listModel, "hasNoListDataListeners")).booleanValue();
+ assertTrue(hasNoListeners);
+ }
+
+ private void verifyHasListeners(ListModel listModel) throws Exception {
+ boolean hasListeners = ((Boolean) ObjectTools.execute(listModel, "hasListDataListeners")).booleanValue();
+ assertTrue(hasListeners);
+ }
+
+ private SimpleCollectionValueModel<String> buildCollectionHolder() {
+ return new SimpleCollectionValueModel<String>(this.buildCollection());
+ }
+
+ private Collection<String> buildCollection() {
+ Bag<String> bag = new HashBag<String>();
+ this.populateCollection(bag);
+ return bag;
+ }
+
+ private SimpleListValueModel<String> buildListHolder() {
+ return new SimpleListValueModel<String>(this.buildList());
+ }
+
+ private List<String> buildList() {
+ List<String> list = new ArrayList<String>();
+ this.populateCollection(list);
+ return list;
+ }
+
+ private void populateCollection(Collection<String> c) {
+ c.add("foo");
+ c.add("bar");
+ c.add("baz");
+ c.add("joo");
+ c.add("jar");
+ c.add("jaz");
+ }
+
+ private SimpleListValueModel<String> buildListHolder2() {
+ return new SimpleListValueModel<String>(this.buildList2());
+ }
+
+ private List<String> buildList2() {
+ List<String> list = new ArrayList<String>();
+ this.populateCollection2(list);
+ return list;
+ }
+
+ private void populateCollection2(Collection<String> c) {
+ c.add("tom");
+ c.add("dick");
+ c.add("harry");
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterUITest.java
new file mode 100644
index 0000000..be9d2b1
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterUITest.java
@@ -0,0 +1,378 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.ListIterator;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.ListModel;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ListAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+/**
+ * an example UI for testing various permutations of the ListModelAdapter
+ */
+@SuppressWarnings("nls")
+public class ListModelAdapterUITest {
+
+ private ModifiablePropertyValueModel<TaskList> taskListHolder;
+ private TextField taskTextField;
+
+ public static void main(String[] args) throws Exception {
+ new ListModelAdapterUITest().exec(args);
+ }
+
+ private ListModelAdapterUITest() {
+ super();
+ }
+
+ private void exec(@SuppressWarnings("unused") String[] args) throws Exception {
+ this.taskListHolder = new SimplePropertyValueModel<TaskList>(new TaskList());
+ this.openWindow();
+ }
+
+ private void openWindow() {
+ JFrame window = new JFrame(this.getClass().getName());
+ window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ window.addWindowListener(this.buildWindowListener());
+ window.getContentPane().add(this.buildMainPanel(), "Center");
+ window.setSize(800, 400);
+ window.setVisible(true);
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private Component buildMainPanel() {
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(this.buildTaskListPanel(), BorderLayout.CENTER);
+ mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ private Component buildTaskListPanel() {
+ JPanel taskListPanel = new JPanel(new GridLayout(0, 1));
+ taskListPanel.add(this.buildPrimitiveTaskListPanel());
+ taskListPanel.add(this.buildDisplayableTaskListPanel());
+ return taskListPanel;
+ }
+
+ private Component buildPrimitiveTaskListPanel() {
+ JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+ taskListPanel.add(this.buildUnsortedPrimitiveListPanel());
+ taskListPanel.add(this.buildStandardSortedPrimitiveListPanel());
+ taskListPanel.add(this.buildCustomSortedPrimitiveListPanel());
+ return taskListPanel;
+ }
+
+ private Component buildDisplayableTaskListPanel() {
+ JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+ taskListPanel.add(this.buildUnsortedDisplayableListPanel());
+ taskListPanel.add(this.buildStandardSortedDisplayableListPanel());
+ taskListPanel.add(this.buildCustomSortedDisplayableListPanel());
+ return taskListPanel;
+ }
+
+ private Component buildUnsortedPrimitiveListPanel() {
+ return this.buildListPanel("primitive unsorted", this.buildUnsortedPrimitiveListModel());
+ }
+
+ private Component buildStandardSortedPrimitiveListPanel() {
+ return this.buildListPanel("primitive sorted", this.buildStandardSortedPrimitiveListModel());
+ }
+
+ private Component buildCustomSortedPrimitiveListPanel() {
+ return this.buildListPanel("primitive reverse sorted", this.buildCustomSortedPrimitiveListModel());
+ }
+
+ private Component buildUnsortedDisplayableListPanel() {
+ return this.buildListPanel("displayable unsorted", this.buildUnsortedDisplayableListModel());
+ }
+
+ private Component buildStandardSortedDisplayableListPanel() {
+ return this.buildListPanel("displayable sorted", this.buildStandardSortedDisplayableListModel());
+ }
+
+ private Component buildCustomSortedDisplayableListPanel() {
+ return this.buildListPanel("displayable reverse sorted", this.buildCustomSortedDisplayableListModel());
+ }
+
+ private ListModel buildUnsortedPrimitiveListModel() {
+ return new ListModelAdapter(this.buildPrimitiveTaskListAdapter());
+ }
+
+ private ListModel buildStandardSortedPrimitiveListModel() {
+ return new ListModelAdapter(new SortedListValueModelWrapper<String>(this.buildPrimitiveTaskListAdapter()));
+ }
+
+ private ListModel buildCustomSortedPrimitiveListModel() {
+ return new ListModelAdapter(new SortedListValueModelWrapper<String>(this.buildPrimitiveTaskListAdapter(), this.buildCustomStringComparator()));
+ }
+
+ private ListModel buildUnsortedDisplayableListModel() {
+ return new ListModelAdapter(this.buildDisplayableTaskListAdapter());
+ }
+
+ private ListModel buildStandardSortedDisplayableListModel() {
+ return new ListModelAdapter(new SortedListValueModelWrapper<Task>(this.buildDisplayableTaskListAdapter()));
+ }
+
+ private ListModel buildCustomSortedDisplayableListModel() {
+ return new ListModelAdapter(new SortedListValueModelWrapper<Task>(this.buildDisplayableTaskListAdapter(), this.buildCustomTaskObjectComparator()));
+ }
+
+ private Component buildListPanel(String label, ListModel listModel) {
+ JPanel listPanel = new JPanel(new BorderLayout());
+ JLabel listLabel = new JLabel(" " + label);
+ listPanel.add(listLabel, BorderLayout.NORTH);
+
+ JList listBox = new JList();
+ listBox.setModel(listModel);
+ listBox.setDoubleBuffered(true);
+ listLabel.setLabelFor(listBox);
+ listPanel.add(new JScrollPane(listBox), BorderLayout.CENTER);
+ return listPanel;
+ }
+
+ private Comparator<String> buildCustomStringComparator() {
+ return new Comparator<String>() {
+ @Override
+ public int compare(String s1, String s2) {
+ return s2.compareTo(s1);
+ }
+ };
+ }
+
+ private Comparator<Task> buildCustomTaskObjectComparator() {
+ return new Comparator<Task>() {
+ @Override
+ public int compare(Task to1, Task to2) {
+ return to2.displayString().compareTo(to1.displayString());
+ }
+ };
+ }
+
+ private ListValueModel<String> buildPrimitiveTaskListAdapter() {
+ return new ListAspectAdapter<TaskList, String>(TaskList.TASK_NAMES_LIST, this.taskList()) {
+ @Override
+ protected ListIterator<String> listIterator_() {
+ return this.subject.taskNames();
+ }
+ };
+ }
+
+ private ListValueModel<Task> buildDisplayableTaskListAdapter() {
+ return new ListAspectAdapter<TaskList, Task>(TaskList.TASKS_LIST, this.taskList()) {
+ @Override
+ protected ListIterator<Task> listIterator_() {
+ return this.subject.tasks();
+ }
+ };
+ }
+
+ private Component buildControlPanel() {
+ JPanel controlPanel = new JPanel(new BorderLayout());
+ controlPanel.add(this.buildAddRemoveTaskPanel(), BorderLayout.CENTER);
+ controlPanel.add(this.buildClearButton(), BorderLayout.EAST);
+ return controlPanel;
+ }
+
+ private Component buildAddRemoveTaskPanel() {
+ JPanel addRemoveTaskPanel = new JPanel(new BorderLayout());
+ addRemoveTaskPanel.add(this.buildAddButton(), BorderLayout.WEST);
+ addRemoveTaskPanel.add(this.buildTaskTextField(), BorderLayout.CENTER);
+ addRemoveTaskPanel.add(this.buildRemoveButton(), BorderLayout.EAST);
+ return addRemoveTaskPanel;
+ }
+
+ private String getTask() {
+ return this.taskTextField.getText();
+ }
+
+ private TaskList taskList() {
+ return this.taskListHolder.getValue();
+ }
+
+ void addTask() {
+ String task = this.getTask();
+ if (task.length() != 0) {
+ this.taskList().addTask(task);
+ }
+ }
+
+ void removeTask() {
+ String task = this.getTask();
+ if (task.length() != 0) {
+ this.taskList().removeTask(task);
+ }
+ }
+
+ void clearTasks() {
+ this.taskList().clearTasks();
+ }
+
+ private TextField buildTaskTextField() {
+ this.taskTextField = new TextField();
+ return this.taskTextField;
+ }
+
+ private JButton buildAddButton() {
+ return new JButton(this.buildAddAction());
+ }
+
+ private Action buildAddAction() {
+ Action action = new AbstractAction("add") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ListModelAdapterUITest.this.addTask();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ private JButton buildRemoveButton() {
+ return new JButton(this.buildRemoveAction());
+ }
+
+ private Action buildRemoveAction() {
+ Action action = new AbstractAction("remove") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ListModelAdapterUITest.this.removeTask();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ private JButton buildClearButton() {
+ return new JButton(this.buildClearAction());
+ }
+
+ private Action buildClearAction() {
+ Action action = new AbstractAction("clear") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ ListModelAdapterUITest.this.clearTasks();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ public class TaskList extends AbstractModel {
+ private List<String> taskNames = new ArrayList<String>();
+ private List<Task> taskObjects = new ArrayList<Task>();
+ public static final String TASK_NAMES_LIST = "taskNames";
+ public static final String TASKS_LIST = "tasks";
+ TaskList() {
+ super();
+ }
+ public ListIterator<String> taskNames() {
+ return this.taskNames.listIterator();
+ }
+ public ListIterator<Task> tasks() {
+ return this.taskObjects.listIterator();
+ }
+ public void addTask(String taskName) {
+ int index = this.taskNames.size();
+ this.taskNames.add(index, taskName);
+ this.fireItemAdded(TASK_NAMES_LIST, index, taskName);
+
+ Task taskObject = new Task(taskName);
+ this.taskObjects.add(index, taskObject);
+ this.fireItemAdded(TASKS_LIST, index, taskObject);
+ }
+ public void removeTask(String taskName) {
+ int index = this.taskNames.indexOf(taskName);
+ if (index != -1) {
+ Object removedTask = this.taskNames.remove(index);
+ this.fireItemRemoved(TASK_NAMES_LIST, index, removedTask);
+ // assume the indexes match...
+ Object removedTaskObject = this.taskObjects.remove(index);
+ this.fireItemRemoved(TASKS_LIST, index, removedTaskObject);
+ }
+ }
+ public void clearTasks() {
+ this.taskNames.clear();
+ this.fireListChanged(TASK_NAMES_LIST, this.taskNames);
+ this.taskObjects.clear();
+ this.fireListChanged(TASKS_LIST, this.taskObjects);
+ }
+ }
+
+ public class Task extends AbstractModel implements Displayable {
+ private String name;
+ private Date creationTimeStamp;
+ public Task(String name) {
+ this.name = name;
+ this.creationTimeStamp = new Date();
+ }
+ @Override
+ public String displayString() {
+ return this.name + ": " + this.creationTimeStamp.getTime();
+ }
+ @Override
+ public Icon icon() {
+ return null;
+ }
+ public String getName() {
+ return this.name;
+ }
+ public void setName(String name) {
+ Object old = this.name;
+ this.name = name;
+ this.firePropertyChanged(DISPLAY_STRING_PROPERTY, old, name);
+ }
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.displayString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListSpinnerModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListSpinnerModelAdapterTests.java
new file mode 100644
index 0000000..1384c53
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListSpinnerModelAdapterTests.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.SpinnerModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class ListSpinnerModelAdapterTests extends TestCase {
+ private ModifiablePropertyValueModel<Object> valueHolder;
+ private SpinnerModel spinnerModelAdapter;
+ boolean eventFired;
+ private static final String[] VALUE_LIST = {"red", "green", "blue"};
+ private static final String DEFAULT_VALUE = VALUE_LIST[0];
+
+ public ListSpinnerModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.valueHolder = new SimplePropertyValueModel<Object>(DEFAULT_VALUE);
+ this.spinnerModelAdapter = new ListSpinnerModelAdapter(this.valueHolder, VALUE_LIST) {
+ @Override
+ protected PropertyChangeListener buildValueChangeListener() {
+ return this.buildValueChangeListener_();
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testSetValueSpinnerModel() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ ListSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertEquals(DEFAULT_VALUE, this.valueHolder.getValue());
+ this.spinnerModelAdapter.setValue(VALUE_LIST[2]);
+ assertTrue(this.eventFired);
+ assertEquals(VALUE_LIST[2], this.valueHolder.getValue());
+ }
+
+ public void testSetValueValueHolder() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ ListSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertEquals(DEFAULT_VALUE, this.spinnerModelAdapter.getValue());
+ this.valueHolder.setValue(VALUE_LIST[2]);
+ assertTrue(this.eventFired);
+ assertEquals(VALUE_LIST[2], this.spinnerModelAdapter.getValue());
+ }
+
+ public void testDefaultValue() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ ListSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertEquals(DEFAULT_VALUE, this.spinnerModelAdapter.getValue());
+
+ this.valueHolder.setValue(VALUE_LIST[2]);
+ assertTrue(this.eventFired);
+ assertEquals(VALUE_LIST[2], this.spinnerModelAdapter.getValue());
+
+ this.eventFired = false;
+ this.valueHolder.setValue(null);
+ assertTrue(this.eventFired);
+ assertEquals(VALUE_LIST[0], this.spinnerModelAdapter.getValue());
+ }
+
+ public void testHasListeners() throws Exception {
+ SimplePropertyValueModel<Object> localValueHolder = (SimplePropertyValueModel<Object>) this.valueHolder;
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.spinnerModelAdapter);
+
+ ChangeListener listener = new TestChangeListener();
+ this.spinnerModelAdapter.addChangeListener(listener);
+ assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasListeners(this.spinnerModelAdapter);
+
+ this.spinnerModelAdapter.removeChangeListener(listener);
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.spinnerModelAdapter);
+ }
+
+ private void verifyHasNoListeners(SpinnerModel adapter) throws Exception {
+ assertEquals(0, ((ListSpinnerModelAdapter) adapter).getChangeListeners().length);
+ }
+
+ private void verifyHasListeners(Object adapter) throws Exception {
+ assertFalse(((ListSpinnerModelAdapter) adapter).getChangeListeners().length == 0);
+ }
+
+
+ private class TestChangeListener implements ChangeListener {
+ TestChangeListener() {
+ super();
+ }
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/NumberSpinnerModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/NumberSpinnerModelAdapterTests.java
new file mode 100644
index 0000000..06121b7
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/NumberSpinnerModelAdapterTests.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.SpinnerModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.NumberSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class NumberSpinnerModelAdapterTests extends TestCase {
+ private ModifiablePropertyValueModel<Number> valueHolder;
+ private SpinnerModel spinnerModelAdapter;
+ boolean eventFired;
+
+ public NumberSpinnerModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.valueHolder = new SimplePropertyValueModel<Number>(new Integer(0));
+ this.spinnerModelAdapter = new NumberSpinnerModelAdapter(this.valueHolder, -33, 33, 1) {
+ @Override
+ protected PropertyChangeListener buildNumberChangeListener() {
+ return this.buildNumberChangeListener_();
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testSetValueSpinnerModel() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ NumberSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ this.spinnerModelAdapter.setValue(new Integer(5));
+ assertTrue(this.eventFired);
+ assertEquals(new Integer(5), this.valueHolder.getValue());
+ }
+
+ public void testSetValueValueHolder() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ NumberSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertEquals(new Integer(0), this.spinnerModelAdapter.getValue());
+ this.valueHolder.setValue(new Integer(7));
+ assertTrue(this.eventFired);
+ assertEquals(new Integer(7), this.spinnerModelAdapter.getValue());
+ }
+
+ public void testDefaultValue() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ NumberSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertEquals(new Integer(0), this.spinnerModelAdapter.getValue());
+ this.valueHolder.setValue(null);
+ assertTrue(this.eventFired);
+ assertEquals(new Integer(-33), this.spinnerModelAdapter.getValue());
+ }
+
+ public void testHasListeners() throws Exception {
+ SimplePropertyValueModel<Number> localValueHolder = (SimplePropertyValueModel<Number>) this.valueHolder;
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.spinnerModelAdapter);
+
+ ChangeListener listener = new TestChangeListener();
+ this.spinnerModelAdapter.addChangeListener(listener);
+ assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasListeners(this.spinnerModelAdapter);
+
+ this.spinnerModelAdapter.removeChangeListener(listener);
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.spinnerModelAdapter);
+ }
+
+ private void verifyHasNoListeners(SpinnerModel adapter) throws Exception {
+ assertEquals(0, ((NumberSpinnerModelAdapter) adapter).getChangeListeners().length);
+ }
+
+ private void verifyHasListeners(Object adapter) throws Exception {
+ assertFalse(((NumberSpinnerModelAdapter) adapter).getChangeListeners().length == 0);
+ }
+
+ public void testNullInitialValue() {
+ this.valueHolder = new SimplePropertyValueModel<Number>();
+ this.spinnerModelAdapter = new NumberSpinnerModelAdapter(this.valueHolder, new Integer(-33), new Integer(33), new Integer(1), new Integer(0)) {
+ @Override
+ protected PropertyChangeListener buildNumberChangeListener() {
+ return this.buildNumberChangeListener_();
+ }
+ };
+
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ NumberSpinnerModelAdapterTests.this.eventFired = true;
+ }
+ });
+ assertEquals(new Integer(0), this.spinnerModelAdapter.getValue());
+ this.valueHolder.setValue(new Integer(7));
+ assertTrue(this.eventFired);
+ assertEquals(new Integer(7), this.spinnerModelAdapter.getValue());
+ }
+
+
+ // ********** inner class **********
+ private class TestChangeListener implements ChangeListener {
+ TestChangeListener() {
+ super();
+ }
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ObjectListSelectionModelTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ObjectListSelectionModelTests.java
new file mode 100644
index 0000000..f9996b3
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ObjectListSelectionModelTests.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.DefaultListModel;
+import javax.swing.ListModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ArrayTools;
+import org.eclipse.persistence.tools.utility.model.value.swing.ObjectListSelectionModel;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+
+@SuppressWarnings("nls")
+public class ObjectListSelectionModelTests extends TestCase {
+ private DefaultListModel listModel;
+ private ObjectListSelectionModel selectionModel;
+
+ public ObjectListSelectionModelTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.listModel = this.buildListModel();
+ this.selectionModel = this.buildSelectionModel(this.listModel);
+ }
+
+ private DefaultListModel buildListModel() {
+ DefaultListModel lm = new DefaultListModel();
+ lm.addElement("foo");
+ lm.addElement("bar");
+ lm.addElement("baz");
+ return lm;
+ }
+
+ private ObjectListSelectionModel buildSelectionModel(ListModel lm) {
+ return new ObjectListSelectionModel(lm);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testListDataListener() {
+ this.selectionModel.addListSelectionListener(this.buildListSelectionListener());
+ this.selectionModel.setSelectionInterval(0, 0);
+ assertEquals("foo", this.selectionModel.selectedValue());
+ this.listModel.set(0, "jar");
+ assertEquals("jar", this.selectionModel.selectedValue());
+ }
+
+ public void testGetSelectedValue() {
+ this.selectionModel.setSelectionInterval(0, 0);
+ assertEquals("foo", this.selectionModel.selectedValue());
+ }
+
+ public void testGetSelectedValues() {
+ this.selectionModel.setSelectionInterval(0, 0);
+ this.selectionModel.addSelectionInterval(2, 2);
+ assertEquals(2, this.selectionModel.selectedValues().length);
+ assertTrue(ArrayTools.contains(this.selectionModel.selectedValues(), "foo"));
+ assertTrue(ArrayTools.contains(this.selectionModel.selectedValues(), "baz"));
+ }
+
+ public void testSetSelectedValue() {
+ this.selectionModel.setSelectedValue("foo");
+ assertEquals(0, this.selectionModel.getMinSelectionIndex());
+ assertEquals(0, this.selectionModel.getMaxSelectionIndex());
+ }
+
+ public void testSetSelectedValues() {
+ this.selectionModel.setSelectedValues(new Object[] {"foo", "baz"});
+ assertEquals(0, this.selectionModel.getMinSelectionIndex());
+ assertEquals(2, this.selectionModel.getMaxSelectionIndex());
+ }
+
+ public void testAddSelectedValue() {
+ this.listModel.addElement("joo");
+ this.listModel.addElement("jar");
+ this.listModel.addElement("jaz");
+ this.selectionModel.setSelectedValue("foo");
+ this.selectionModel.addSelectedValue("jaz");
+ assertEquals(0, this.selectionModel.getMinSelectionIndex());
+ assertEquals(5, this.selectionModel.getMaxSelectionIndex());
+ assertTrue(this.selectionModel.isSelectedIndex(0));
+ assertFalse(this.selectionModel.isSelectedIndex(1));
+ assertFalse(this.selectionModel.isSelectedIndex(2));
+ assertFalse(this.selectionModel.isSelectedIndex(3));
+ assertFalse(this.selectionModel.isSelectedIndex(4));
+ assertTrue(this.selectionModel.isSelectedIndex(5));
+ }
+
+ public void testAddSelectedValues() {
+ this.listModel.addElement("joo");
+ this.listModel.addElement("jar");
+ this.listModel.addElement("jaz");
+ this.selectionModel.setSelectedValue("foo");
+ this.selectionModel.addSelectedValues(new Object[] {"bar", "jar"});
+ assertEquals(0, this.selectionModel.getMinSelectionIndex());
+ assertEquals(4, this.selectionModel.getMaxSelectionIndex());
+ assertTrue(this.selectionModel.isSelectedIndex(0));
+ assertTrue(this.selectionModel.isSelectedIndex(1));
+ assertFalse(this.selectionModel.isSelectedIndex(2));
+ assertFalse(this.selectionModel.isSelectedIndex(3));
+ assertTrue(this.selectionModel.isSelectedIndex(4));
+ assertFalse(this.selectionModel.isSelectedIndex(5));
+ }
+
+ public void testRemoveSelectedValue() {
+ this.listModel.addElement("joo");
+ this.listModel.addElement("jar");
+ this.listModel.addElement("jaz");
+ this.selectionModel.setSelectedValues(new Object[] {"foo", "baz", "jar"});
+ this.selectionModel.removeSelectedValue("jar");
+ assertEquals(0, this.selectionModel.getMinSelectionIndex());
+ assertEquals(2, this.selectionModel.getMaxSelectionIndex());
+ assertTrue(this.selectionModel.isSelectedIndex(0));
+ assertFalse(this.selectionModel.isSelectedIndex(1));
+ assertTrue(this.selectionModel.isSelectedIndex(2));
+ assertFalse(this.selectionModel.isSelectedIndex(3));
+ assertFalse(this.selectionModel.isSelectedIndex(4));
+ assertFalse(this.selectionModel.isSelectedIndex(5));
+ }
+
+ public void testRemoveSelectedValues() {
+ this.listModel.addElement("joo");
+ this.listModel.addElement("jar");
+ this.listModel.addElement("jaz");
+ this.selectionModel.setSelectedValues(new Object[] {"foo", "baz", "joo", "jar"});
+ this.selectionModel.removeSelectedValues(new Object[] {"foo", "joo"});
+ assertEquals(2, this.selectionModel.getMinSelectionIndex());
+ assertEquals(4, this.selectionModel.getMaxSelectionIndex());
+ assertFalse(this.selectionModel.isSelectedIndex(0));
+ assertFalse(this.selectionModel.isSelectedIndex(1));
+ assertTrue(this.selectionModel.isSelectedIndex(2));
+ assertFalse(this.selectionModel.isSelectedIndex(3));
+ assertTrue(this.selectionModel.isSelectedIndex(4));
+ assertFalse(this.selectionModel.isSelectedIndex(5));
+ }
+
+ public void testGetAnchorSelectedValue() {
+ this.selectionModel.setAnchorSelectionIndex(1);
+ assertEquals("bar", this.selectionModel.getAnchorSelectedValue());
+ }
+
+ public void testGetLeadSelectedValue() {
+ this.selectionModel.setSelectedValue("bar");
+ assertEquals("bar", this.selectionModel.getLeadSelectedValue());
+ this.selectionModel.setSelectedValues(new Object[] {"foo", "baz"});
+ assertEquals("baz", this.selectionModel.getLeadSelectedValue());
+ }
+
+ public void testGetMinMaxSelectedValue() {
+ this.listModel.addElement("joo");
+ this.listModel.addElement("jar");
+ this.listModel.addElement("jaz");
+ this.selectionModel.setSelectedValue("foo");
+ this.selectionModel.addSelectedValues(new Object[] {"bar", "jar"});
+ assertEquals("foo", this.selectionModel.getMinSelectedValue());
+ assertEquals("jar", this.selectionModel.getMaxSelectedValue());
+ }
+
+ public void testValueIsSelected() {
+ this.listModel.addElement("joo");
+ this.listModel.addElement("jar");
+ this.listModel.addElement("jaz");
+ this.selectionModel.setSelectedValue("foo");
+ this.selectionModel.addSelectedValues(new Object[] {"bar", "jar"});
+ assertTrue(this.selectionModel.valueIsSelected("foo"));
+ assertTrue(this.selectionModel.valueIsSelected("bar"));
+ assertTrue(this.selectionModel.valueIsSelected("jar"));
+ assertFalse(this.selectionModel.valueIsSelected("baz"));
+ }
+
+ public void testHasListeners() throws Exception {
+ ListSelectionListener listener = this.buildListSelectionListener();
+ assertEquals(0, this.listModel.getListDataListeners().length);
+ this.selectionModel.addListSelectionListener(listener);
+ assertEquals(1, this.listModel.getListDataListeners().length);
+ this.selectionModel.removeListSelectionListener(listener);
+ assertEquals(0, this.listModel.getListDataListeners().length);
+ }
+
+ private ListSelectionListener buildListSelectionListener() {
+ return new ListSelectionListener() {
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ // do nothing for now...
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/PrimitiveListTreeModelTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/PrimitiveListTreeModelTests.java
new file mode 100644
index 0000000..d1cc289
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/PrimitiveListTreeModelTests.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ListIterator;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeModel;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.iterator.ReadOnlyListIterator;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.PrimitiveListTreeModel;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class PrimitiveListTreeModelTests extends TestCase {
+ TestModel testModel;
+ private TreeModel treeModel;
+
+ public PrimitiveListTreeModelTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.testModel = this.buildTestModel();
+ this.treeModel = this.buildTreeModel();
+ }
+
+ private TestModel buildTestModel() {
+ return new TestModel();
+ }
+
+ private TreeModel buildTreeModel() {
+ return new PrimitiveListTreeModel(this.buildListValueModel()) {
+ @Override
+ protected void primitiveChanged(int index, Object newValue) {
+ if ( ! newValue.equals("")) {
+ PrimitiveListTreeModelTests.this.testModel.replaceName(index, (String) newValue);
+ }
+ }
+ @Override
+ protected ListChangeListener buildListChangeListener() {
+ return this.buildListChangeListener_();
+ }
+ };
+ }
+
+ private ListValueModel<?> buildListValueModel() {
+ return new ListAspectAdapter<TestModel, String>(TestModel.NAMES_LIST, this.testModel) {
+ @Override
+ protected ListIterator<String> listIterator_() {
+ return this.subject.names();
+ }
+ @Override
+ public String get(int index) {
+ return this.subject.getName(index);
+ }
+ @Override
+ public int size() {
+ return this.subject.namesSize();
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testAddPrimitive() {
+ this.treeModel.addTreeModelListener(new TestTreeModelListener() {
+ @Override
+ public void treeNodesInserted(TreeModelEvent e) {
+ PrimitiveListTreeModelTests.this.verifyTreeModelEvent(e, new int[] {0}, new String[] {"foo"});
+ }
+ });
+ this.testModel.addName("foo");
+ }
+
+ public void testRemovePrimitive() {
+ this.testModel.addName("foo");
+ this.testModel.addName("bar");
+ this.testModel.addName("baz");
+ this.treeModel.addTreeModelListener(new TestTreeModelListener() {
+ @Override
+ public void treeNodesRemoved(TreeModelEvent e) {
+ PrimitiveListTreeModelTests.this.verifyTreeModelEvent(e, new int[] {1}, new String[] {"bar"});
+ }
+ });
+ String name = this.testModel.removeName(1);
+ assertEquals("bar", name);
+ }
+
+ public void testReplacePrimitive() {
+ this.testModel.addName("foo");
+ this.testModel.addName("bar");
+ this.testModel.addName("baz");
+ this.treeModel.addTreeModelListener(new TestTreeModelListener() {
+ @Override
+ public void treeNodesChanged(TreeModelEvent e) {
+ PrimitiveListTreeModelTests.this.verifyTreeModelEvent(e, new int[] {1}, new String[] {"jar"});
+ }
+ });
+ String name = this.testModel.replaceName(1, "jar");
+ assertEquals("bar", name);
+ }
+
+ void verifyTreeModelEvent(TreeModelEvent e, int[] expectedChildIndices, String[] expectedNames) {
+ assertTrue(Arrays.equals(expectedChildIndices, e.getChildIndices()));
+ Object[] actualChildren = e.getChildren();
+ assertEquals(expectedNames.length, actualChildren.length);
+ for (int i = 0; i < expectedNames.length; i++) {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) actualChildren[i];
+ assertEquals(expectedNames[i], node.getUserObject());
+ }
+ assertEquals(1, e.getPath().length);
+ assertEquals(this.treeModel.getRoot(), e.getPath()[0]);
+ assertEquals(this.treeModel, e.getSource());
+ }
+
+
+// ********** inner classes **********
+
+ class TestModel extends AbstractModel {
+ private final List<String> names;
+ static final String NAMES_LIST = "names";
+
+ TestModel() {
+ super();
+ this.names = new ArrayList<String>();
+ }
+
+ public ListIterator<String> names() {
+ return new ReadOnlyListIterator<String>(this.names);
+ }
+ public int namesSize() {
+ return this.names.size();
+ }
+ public String getName(int index) {
+ return this.names.get(index);
+ }
+ public void addName(int index, String name) {
+ this.addItemToList(index, name, this.names, NAMES_LIST);
+ }
+ public void addName(String name) {
+ this.addName(this.namesSize(), name);
+ }
+ public void addNames(int index, List<String> list) {
+ this.addItemsToList(index, this.names, list, NAMES_LIST);
+ }
+ public void addNames(List<String> list) {
+ this.addNames(this.namesSize(), list);
+ }
+ public String removeName(int index) {
+ return this.removeItemFromList(index, this.names, NAMES_LIST);
+ }
+ public List<String> removeNames(int index, int length) {
+ return this.removeItemsFromList(index, length, this.names, NAMES_LIST);
+ }
+ public String replaceName(int index, String newName) {
+ return this.setItemInList(index, newName, this.names, NAMES_LIST);
+ }
+ }
+
+
+ public class TestTreeModelListener implements TreeModelListener {
+ @Override
+ public void treeNodesChanged(TreeModelEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void treeNodesInserted(TreeModelEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void treeNodesRemoved(TreeModelEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void treeStructureChanged(TreeModelEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterTests.java
new file mode 100644
index 0000000..5f598fa
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterTests.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.ButtonModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.RadioButtonModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class RadioButtonModelAdapterTests extends TestCase {
+ private ModifiablePropertyValueModel<Object> valueHolder;
+
+ private ButtonModel redButtonModelAdapter;
+ private ChangeListener redListener;
+ boolean redEventFired;
+
+ private ButtonModel greenButtonModelAdapter;
+ private ChangeListener greenListener;
+ boolean greenEventFired;
+
+ private ButtonModel blueButtonModelAdapter;
+ private ChangeListener blueListener;
+ boolean blueEventFired;
+
+// private ButtonGroup buttonGroup; // DO NOT use a ButtonGroup
+
+ private static final String RED = "red";
+ private static final String GREEN = "green";
+ private static final String BLUE = "blue";
+
+ public RadioButtonModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.valueHolder = new SimplePropertyValueModel<Object>(null);
+// buttonGroup = new ButtonGroup();
+
+ this.redButtonModelAdapter = this.buildButtonModel(this.valueHolder, RED);
+// this.redButtonModelAdapter.setGroup(buttonGroup);
+ this.redListener = new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ RadioButtonModelAdapterTests.this.redEventFired = true;
+ }
+ };
+
+ this.greenButtonModelAdapter = this.buildButtonModel(this.valueHolder, GREEN);
+// this.greenButtonModelAdapter.setGroup(buttonGroup);
+ this.greenListener = new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ RadioButtonModelAdapterTests.this.greenEventFired = true;
+ }
+ };
+
+ this.blueButtonModelAdapter = this.buildButtonModel(this.valueHolder, BLUE);
+// this.blueButtonModelAdapter.setGroup(buttonGroup);
+ this.blueListener = new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ RadioButtonModelAdapterTests.this.blueEventFired = true;
+ }
+ };
+
+ this.clearFlags();
+ }
+
+ private ButtonModel buildButtonModel(ModifiablePropertyValueModel<Object> pvm, Object buttonValue) {
+ return new RadioButtonModelAdapter(pvm, buttonValue) {
+ @Override
+ protected PropertyChangeListener buildBooleanChangeListener() {
+ return this.buildBooleanChangeListener_();
+ }
+ };
+ }
+
+ private void listenToModelAdapters() {
+ this.redButtonModelAdapter.addChangeListener(this.redListener);
+ this.greenButtonModelAdapter.addChangeListener(this.greenListener);
+ this.blueButtonModelAdapter.addChangeListener(this.blueListener);
+ }
+
+ private void clearFlags() {
+ this.redEventFired = false;
+ this.greenEventFired = false;
+ this.blueEventFired = false;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testSetSelected() throws Exception {
+ this.listenToModelAdapters();
+
+ this.greenButtonModelAdapter.setSelected(true);
+ assertFalse(this.redEventFired);
+ assertTrue(this.greenEventFired);
+ assertFalse(this.blueEventFired);
+ assertEquals(GREEN, this.valueHolder.getValue());
+
+ this.clearFlags();
+ this.blueButtonModelAdapter.setSelected(true);
+ assertFalse(this.redEventFired);
+ assertTrue(this.greenEventFired);
+ assertTrue(this.blueEventFired);
+ assertEquals(BLUE, this.valueHolder.getValue());
+
+ this.clearFlags();
+ this.redButtonModelAdapter.setSelected(true);
+ assertTrue(this.redEventFired);
+ assertFalse(this.greenEventFired);
+ assertTrue(this.blueEventFired);
+ assertEquals(RED, this.valueHolder.getValue());
+ }
+
+ public void testSetValue() throws Exception {
+ this.listenToModelAdapters();
+
+ this.greenButtonModelAdapter.setSelected(true);
+
+ this.clearFlags();
+ this.valueHolder.setValue(BLUE);
+ assertFalse(this.redEventFired);
+ assertTrue(this.greenEventFired);
+ assertTrue(this.blueEventFired);
+ assertFalse(this.redButtonModelAdapter.isSelected());
+ assertFalse(this.greenButtonModelAdapter.isSelected());
+ assertTrue(this.blueButtonModelAdapter.isSelected());
+
+ this.clearFlags();
+ this.valueHolder.setValue(RED);
+ assertTrue(this.redEventFired);
+ assertFalse(this.greenEventFired);
+ assertTrue(this.blueEventFired);
+ assertTrue(this.redButtonModelAdapter.isSelected());
+ assertFalse(this.greenButtonModelAdapter.isSelected());
+ assertFalse(this.blueButtonModelAdapter.isSelected());
+ }
+
+ public void testDefaultValue() throws Exception {
+ this.listenToModelAdapters();
+
+ this.valueHolder.setValue(GREEN);
+ assertFalse(this.redButtonModelAdapter.isSelected());
+ assertTrue(this.greenButtonModelAdapter.isSelected());
+ assertFalse(this.blueButtonModelAdapter.isSelected());
+
+ this.clearFlags();
+ this.valueHolder.setValue(null);
+ assertFalse(this.redEventFired);
+ assertTrue(this.greenEventFired);
+ assertFalse(this.blueEventFired);
+ assertFalse(this.redButtonModelAdapter.isSelected());
+ assertFalse(this.greenButtonModelAdapter.isSelected());
+ assertFalse(this.blueButtonModelAdapter.isSelected());
+
+ this.clearFlags();
+ this.valueHolder.setValue(BLUE);
+ assertFalse(this.redEventFired);
+ assertFalse(this.greenEventFired);
+ assertTrue(this.blueEventFired);
+ assertFalse(this.redButtonModelAdapter.isSelected());
+ assertFalse(this.greenButtonModelAdapter.isSelected());
+ assertTrue(this.blueButtonModelAdapter.isSelected());
+ }
+
+ public void testHasListeners() throws Exception {
+ SimplePropertyValueModel<Object> localValueHolder = (SimplePropertyValueModel<Object>) this.valueHolder;
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.redButtonModelAdapter);
+ this.verifyHasNoListeners(this.greenButtonModelAdapter);
+ this.verifyHasNoListeners(this.blueButtonModelAdapter);
+
+ ChangeListener listener = new TestChangeListener();
+ this.redButtonModelAdapter.addChangeListener(listener);
+ assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasListeners(this.redButtonModelAdapter);
+ this.verifyHasNoListeners(this.greenButtonModelAdapter);
+ this.verifyHasNoListeners(this.blueButtonModelAdapter);
+
+ this.redButtonModelAdapter.removeChangeListener(listener);
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.redButtonModelAdapter);
+ this.verifyHasNoListeners(this.greenButtonModelAdapter);
+ this.verifyHasNoListeners(this.blueButtonModelAdapter);
+ }
+
+ private void verifyHasNoListeners(Object model) throws Exception {
+ EventListenerList listenerList = (EventListenerList) ObjectTools.get(model, "listenerList");
+ assertEquals(0, listenerList.getListenerList().length);
+ }
+
+ private void verifyHasListeners(Object model) throws Exception {
+ EventListenerList listenerList = (EventListenerList) ObjectTools.get(model, "listenerList");
+ assertFalse(listenerList.getListenerList().length == 0);
+ }
+
+
+ private class TestChangeListener implements ChangeListener {
+ TestChangeListener() {
+ super();
+ }
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterUITest.java
new file mode 100644
index 0000000..a1d7c14
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterUITest.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.ArrayTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.RadioButtonModelAdapter;
+
+/**
+ * Play around with a set of radio buttons.
+ */
+@SuppressWarnings("nls")
+public class RadioButtonModelAdapterUITest {
+
+ private TestModel testModel;
+ private ModifiablePropertyValueModel<TestModel> testModelHolder;
+ private ModifiablePropertyValueModel<Object> colorHolder;
+ private ButtonModel redButtonModel;
+ private ButtonModel greenButtonModel;
+ private ButtonModel blueButtonModel;
+
+ public static void main(String[] args) throws Exception {
+ new RadioButtonModelAdapterUITest().exec();
+ }
+
+ private RadioButtonModelAdapterUITest() {
+ super();
+ }
+
+ private void exec() throws Exception {
+ this.testModel = new TestModel();
+ this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+ this.colorHolder = this.buildColorHolder(this.testModelHolder);
+ this.redButtonModel = this.buildRadioButtonModelAdapter(this.colorHolder, TestModel.RED);
+ this.greenButtonModel = this.buildRadioButtonModelAdapter(this.colorHolder, TestModel.GREEN);
+ this.blueButtonModel = this.buildRadioButtonModelAdapter(this.colorHolder, TestModel.BLUE);
+ this.openWindow();
+ }
+
+ private ModifiablePropertyValueModel<Object> buildColorHolder(PropertyValueModel<TestModel> subjectHolder) {
+ return new PropertyAspectAdapter<TestModel, Object>(subjectHolder, TestModel.COLOR_PROPERTY) {
+ @Override
+ protected Object buildValue_() {
+ return this.subject.getColor();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setColor((String) value);
+ }
+ };
+ }
+
+ private ButtonModel buildRadioButtonModelAdapter(ModifiablePropertyValueModel<Object> colorPVM, String color) {
+ return new RadioButtonModelAdapter(colorPVM, color);
+ }
+
+ private void openWindow() {
+ JFrame window = new JFrame(this.getClass().getName());
+ window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ window.addWindowListener(this.buildWindowListener());
+ window.getContentPane().add(this.buildMainPanel(), "Center");
+ window.setSize(400, 100);
+ window.setLocation(200, 200);
+ window.setVisible(true);
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private Component buildMainPanel() {
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(this.buildRadioButtonPanel(), BorderLayout.NORTH);
+ mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ private Component buildRadioButtonPanel() {
+ JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+ taskListPanel.add(this.buildRedRadioButton());
+ taskListPanel.add(this.buildGreenRadioButton());
+ taskListPanel.add(this.buildBlueRadioButton());
+ return taskListPanel;
+ }
+
+ private JRadioButton buildRedRadioButton() {
+ JRadioButton radioButton = new JRadioButton();
+ radioButton.setText("red");
+ radioButton.setModel(this.redButtonModel);
+ return radioButton;
+ }
+
+ private JRadioButton buildGreenRadioButton() {
+ JRadioButton radioButton = new JRadioButton();
+ radioButton.setText("green");
+ radioButton.setModel(this.greenButtonModel);
+ return radioButton;
+ }
+
+ private JRadioButton buildBlueRadioButton() {
+ JRadioButton radioButton = new JRadioButton();
+ radioButton.setText("blue");
+ radioButton.setModel(this.blueButtonModel);
+ return radioButton;
+ }
+
+ private Component buildControlPanel() {
+ JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+ controlPanel.add(this.buildResetColorButton());
+ controlPanel.add(this.buildClearModelButton());
+ controlPanel.add(this.buildRestoreModelButton());
+ controlPanel.add(this.buildPrintModelButton());
+ return controlPanel;
+ }
+
+ private JButton buildResetColorButton() {
+ return new JButton(this.buildResetColorAction());
+ }
+
+ private Action buildResetColorAction() {
+ Action action = new AbstractAction("reset color") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ RadioButtonModelAdapterUITest.this.resetColor();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void resetColor() {
+ this.testModel.setColor(TestModel.DEFAULT_COLOR);
+ }
+
+ private JButton buildClearModelButton() {
+ return new JButton(this.buildClearModelAction());
+ }
+
+ private Action buildClearModelAction() {
+ Action action = new AbstractAction("clear model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ RadioButtonModelAdapterUITest.this.clearModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void clearModel() {
+ this.testModelHolder.setValue(null);
+ }
+
+ private JButton buildRestoreModelButton() {
+ return new JButton(this.buildRestoreModelAction());
+ }
+
+ private Action buildRestoreModelAction() {
+ Action action = new AbstractAction("restore model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ RadioButtonModelAdapterUITest.this.restoreModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void restoreModel() {
+ this.testModelHolder.setValue(this.testModel);
+ }
+
+ private JButton buildPrintModelButton() {
+ return new JButton(this.buildPrintModelAction());
+ }
+
+ private Action buildPrintModelAction() {
+ Action action = new AbstractAction("print model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ RadioButtonModelAdapterUITest.this.printModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void printModel() {
+ System.out.println(this.testModel);
+ }
+
+
+ private static class TestModel extends AbstractModel {
+ private String color;
+ public static final String COLOR_PROPERTY = "color";
+ public static final String RED = "red";
+ public static final String GREEN = "green";
+ public static final String BLUE = "blue";
+ public static final String DEFAULT_COLOR = RED;
+ public static final String[] VALID_COLORS = {
+ RED,
+ GREEN,
+ BLUE
+ };
+
+ public TestModel() {
+ this(DEFAULT_COLOR);
+ }
+ public TestModel(String color) {
+ this.color = color;
+ }
+ public String getColor() {
+ return this.color;
+ }
+ public void setColor(String color) {
+ if ( ! ArrayTools.contains(VALID_COLORS, color)) {
+ throw new IllegalArgumentException(color);
+ }
+ Object old = this.color;
+ this.color = color;
+ this.firePropertyChanged(COLOR_PROPERTY, old, color);
+ }
+ @Override
+ public String toString() {
+ return "TestModel(" + this.color + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ReadOnlyTableModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ReadOnlyTableModelAdapterUITest.java
new file mode 100644
index 0000000..dbfc8f2
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ReadOnlyTableModelAdapterUITest.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import org.eclipse.persistence.tools.utility.model.value.swing.TableModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TableModelAdapterTests.PersonColumnAdapter;
+
+/**
+ * Make it easy to test the table model adapter and
+ * renderers without any editing allowed.
+ */
+public class ReadOnlyTableModelAdapterUITest
+ extends TableModelAdapterUITest
+{
+ public static void main(String[] args) throws Exception {
+ new ReadOnlyTableModelAdapterUITest().exec(args);
+ }
+
+ protected ReadOnlyTableModelAdapterUITest() {
+ super();
+ }
+
+ @Override
+ protected TableModelAdapter.ColumnAdapter buildColumnAdapter() {
+ return new PersonColumnAdapter() {
+ @Override
+ public boolean columnIsEditable(int index) {
+ return false;
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterTests.java
new file mode 100644
index 0000000..90c5462
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterTests.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.SpinnerModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.SpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class SpinnerModelAdapterTests extends TestCase {
+ private ModifiablePropertyValueModel<Object> valueHolder;
+ SpinnerModel spinnerModelAdapter;
+ boolean eventFired;
+
+ public SpinnerModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.valueHolder = new SimplePropertyValueModel<Object>(new Integer(0));
+ this.spinnerModelAdapter = new SpinnerModelAdapter(this.valueHolder) {
+ @Override
+ protected PropertyChangeListener buildValueListener() {
+ return this.buildValueListener_();
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testSetValueSpinnerModel() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ SpinnerModelAdapterTests.this.eventFired = true;
+ assertEquals(SpinnerModelAdapterTests.this.spinnerModelAdapter, e.getSource());
+ }
+ });
+ this.spinnerModelAdapter.setValue(new Integer(5));
+ assertTrue(this.eventFired);
+ assertEquals(new Integer(5), this.valueHolder.getValue());
+ }
+
+ public void testSetValueValueHolder() throws Exception {
+ this.eventFired = false;
+ this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ SpinnerModelAdapterTests.this.eventFired = true;
+ assertEquals(SpinnerModelAdapterTests.this.spinnerModelAdapter, e.getSource());
+ }
+ });
+ assertEquals(new Integer(0), this.spinnerModelAdapter.getValue());
+ this.valueHolder.setValue(new Integer(7));
+ assertTrue(this.eventFired);
+ assertEquals(new Integer(7), this.spinnerModelAdapter.getValue());
+ }
+
+ public void testHasListeners() throws Exception {
+ SimplePropertyValueModel<Object> localValueHolder = (SimplePropertyValueModel<Object>) this.valueHolder;
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.spinnerModelAdapter);
+
+ ChangeListener listener = new TestChangeListener();
+ this.spinnerModelAdapter.addChangeListener(listener);
+ assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasListeners(this.spinnerModelAdapter);
+
+ this.spinnerModelAdapter.removeChangeListener(listener);
+ assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ this.verifyHasNoListeners(this.spinnerModelAdapter);
+ }
+
+ private void verifyHasNoListeners(Object adapter) throws Exception {
+ Object delegate = ObjectTools.get(adapter, "delegate");
+ Object[] listeners = (Object[]) ObjectTools.execute(delegate, "getChangeListeners");
+ assertEquals(0, listeners.length);
+ }
+
+ private void verifyHasListeners(Object adapter) throws Exception {
+ Object delegate = ObjectTools.get(adapter, "delegate");
+ Object[] listeners = (Object[]) ObjectTools.execute(delegate, "getChangeListeners");
+ assertFalse(listeners.length == 0);
+ }
+
+
+ private class TestChangeListener implements ChangeListener {
+ TestChangeListener() {
+ super();
+ }
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterUITest.java
new file mode 100644
index 0000000..a117c36
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterUITest.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.Calendar;
+import java.util.Date;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerModel;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.ArrayTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.DateSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.NumberSpinnerModelAdapter;
+
+/**
+ * Play around with a set of spinners.
+ */
+@SuppressWarnings("nls")
+public class SpinnerModelAdapterUITest {
+
+ private TestModel testModel;
+ private ModifiablePropertyValueModel<TestModel> testModelHolder;
+
+ private ModifiablePropertyValueModel<Object> birthDateHolder;
+ private SpinnerModel birthDateSpinnerModel;
+
+ private ModifiablePropertyValueModel<Number> ageHolder;
+ private SpinnerModel ageSpinnerModel;
+
+ private ModifiablePropertyValueModel<Object> eyeColorHolder;
+ private SpinnerModel eyeColorSpinnerModel;
+
+
+ public static void main(String[] args) throws Exception {
+ new SpinnerModelAdapterUITest().exec();
+ }
+
+ private SpinnerModelAdapterUITest() {
+ super();
+ }
+
+ private void exec() throws Exception {
+ this.testModel = new TestModel();
+ this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+
+ this.birthDateHolder = this.buildBirthDateHolder(this.testModelHolder);
+ this.birthDateSpinnerModel = this.buildBirthDateSpinnerModel(this.birthDateHolder);
+
+ this.ageHolder = this.buildAgeHolder(this.testModelHolder);
+ this.ageSpinnerModel = this.buildAgeSpinnerModel(this.ageHolder);
+
+ this.eyeColorHolder = this.buildEyeColorHolder(this.testModelHolder);
+ this.eyeColorSpinnerModel = this.buildEyeColorSpinnerModel(this.eyeColorHolder);
+
+ this.openWindow();
+ }
+
+ private ModifiablePropertyValueModel<Object> buildBirthDateHolder(PropertyValueModel<TestModel> vm) {
+ return new PropertyAspectAdapter<TestModel, Object>(vm, TestModel.BIRTH_DATE_PROPERTY) {
+ @Override
+ protected Object buildValue_() {
+ return this.subject.getBirthDate();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setBirthDate((Date) value);
+ }
+ };
+ }
+
+ private SpinnerModel buildBirthDateSpinnerModel(ModifiablePropertyValueModel<Object> valueHolder) {
+ return new DateSpinnerModelAdapter(valueHolder);
+ }
+
+ private ModifiablePropertyValueModel<Number> buildAgeHolder(PropertyValueModel<TestModel> vm) {
+ return new PropertyAspectAdapter<TestModel, Number>(vm, TestModel.AGE_PROPERTY) {
+ @Override
+ protected Number buildValue_() {
+ return new Integer(this.subject.getAge());
+ }
+ @Override
+ protected void setValue_(Number value) {
+ this.subject.setAge(value.intValue());
+ }
+ };
+ }
+
+ private SpinnerModel buildAgeSpinnerModel(ModifiablePropertyValueModel<Number> valueHolder) {
+ return new NumberSpinnerModelAdapter(valueHolder, valueHolder.getValue().intValue(), TestModel.MIN_AGE, TestModel.MAX_AGE, 1);
+ }
+
+ private ModifiablePropertyValueModel<Object> buildEyeColorHolder(PropertyValueModel<TestModel> vm) {
+ return new PropertyAspectAdapter<TestModel, Object>(vm, TestModel.EYE_COLOR_PROPERTY) {
+ @Override
+ protected Object buildValue_() {
+ return this.subject.getEyeColor();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setEyeColor((String) value);
+ }
+ };
+ }
+
+ private SpinnerModel buildEyeColorSpinnerModel(ModifiablePropertyValueModel<Object> valueHolder) {
+ return new ListSpinnerModelAdapter(valueHolder, TestModel.VALID_EYE_COLORS);
+ }
+
+ private void openWindow() {
+ JFrame window = new JFrame(this.getClass().getName());
+ window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ window.addWindowListener(this.buildWindowListener());
+ window.getContentPane().add(this.buildMainPanel(), "Center");
+ window.setSize(600, 100);
+ window.setVisible(true);
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private Component buildMainPanel() {
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(this.buildSpinnerPanel(), BorderLayout.NORTH);
+ mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ private Component buildSpinnerPanel() {
+ JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+ taskListPanel.add(this.buildBirthDateSpinner());
+ taskListPanel.add(this.buildAgeSpinner());
+ taskListPanel.add(this.buildEyeColorSpinner());
+ return taskListPanel;
+ }
+
+ private JSpinner buildBirthDateSpinner() {
+ return new JSpinner(this.birthDateSpinnerModel);
+ }
+
+ private JSpinner buildAgeSpinner() {
+ return new JSpinner(this.ageSpinnerModel);
+ }
+
+ private JSpinner buildEyeColorSpinner() {
+ return new JSpinner(this.eyeColorSpinnerModel);
+ }
+
+ private Component buildControlPanel() {
+ JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+ controlPanel.add(this.buildResetModelButton());
+ controlPanel.add(this.buildClearModelButton());
+ controlPanel.add(this.buildRestoreModelButton());
+ controlPanel.add(this.buildPrintModelButton());
+ return controlPanel;
+ }
+
+ private JButton buildResetModelButton() {
+ return new JButton(this.buildResetModelAction());
+ }
+
+ private Action buildResetModelAction() {
+ Action action = new AbstractAction("reset model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ SpinnerModelAdapterUITest.this.resetModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void resetModel() {
+ this.testModel.setBirthDate(TestModel.DEFAULT_BIRTH_DATE);
+ this.testModel.setEyeColor(TestModel.DEFAULT_EYE_COLOR);
+ }
+
+ private JButton buildClearModelButton() {
+ return new JButton(this.buildClearModelAction());
+ }
+
+ private Action buildClearModelAction() {
+ Action action = new AbstractAction("clear model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ SpinnerModelAdapterUITest.this.clearModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void clearModel() {
+ this.testModelHolder.setValue(null);
+ }
+
+ private JButton buildRestoreModelButton() {
+ return new JButton(this.buildRestoreModelAction());
+ }
+
+ private Action buildRestoreModelAction() {
+ Action action = new AbstractAction("restore model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ SpinnerModelAdapterUITest.this.restoreModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void restoreModel() {
+ this.testModelHolder.setValue(this.testModel);
+ }
+
+ private JButton buildPrintModelButton() {
+ return new JButton(this.buildPrintModelAction());
+ }
+
+ private Action buildPrintModelAction() {
+ Action action = new AbstractAction("print model") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ SpinnerModelAdapterUITest.this.printModel();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void printModel() {
+ System.out.println("birth date: " + this.testModel.getBirthDate());
+ System.out.println("age: " + this.testModel.getAge());
+ System.out.println("eyes: " + this.testModel.getEyeColor());
+ }
+
+
+ static class TestModel extends AbstractModel {
+ private Calendar birthCal = Calendar.getInstance();
+ // "virtual" properties
+ public static final String BIRTH_DATE_PROPERTY = "birthDate";
+ public static final String AGE_PROPERTY = "age";
+ public static final Date DEFAULT_BIRTH_DATE = new Date();
+ public static final int DEFAULT_AGE = 0;
+ public static final int MIN_AGE = 0;
+ public static final int MAX_AGE = 150;
+ private String eyeColor;
+ public static final String EYE_COLOR_PROPERTY = "eyeColor";
+ public static final String[] VALID_EYE_COLORS = {"blue", "brown", "green", "hazel", "pink"};
+ public static final String DEFAULT_EYE_COLOR = VALID_EYE_COLORS[3];
+
+ TestModel() {
+ this(DEFAULT_BIRTH_DATE, DEFAULT_EYE_COLOR);
+ }
+ public TestModel(Date birthDate, String eyeColor) {
+ this.setBirthDate(birthDate);
+ this.setEyeColor(eyeColor);
+ }
+ public Date getBirthDate() {
+ return (Date) this.birthCal.getTime().clone();
+ }
+ public void setBirthDate(Date birthDate) {
+ Date oldBirthDate = this.getBirthDate();
+ int oldAge = this.getAge();
+ this.birthCal.setTimeInMillis(birthDate.getTime());
+ int newAge = this.getAge();
+ if (newAge < MIN_AGE || newAge > MAX_AGE) {
+ throw new IllegalArgumentException(birthDate.toString());
+ }
+ this.firePropertyChanged(BIRTH_DATE_PROPERTY, oldBirthDate, this.getBirthDate());
+ this.firePropertyChanged(AGE_PROPERTY, oldAge, newAge);
+ }
+ public int getAge() {
+ Calendar currentCal = Calendar.getInstance();
+ int age = currentCal.get(Calendar.YEAR) - this.birthCal.get(Calendar.YEAR);
+ if (currentCal.get(Calendar.MONTH) < this.birthCal.get(Calendar.MONTH)) {
+ age--;
+ } else if (currentCal.get(Calendar.MONTH) == this.birthCal.get(Calendar.MONTH)) {
+ if (currentCal.get(Calendar.DAY_OF_MONTH) < this.birthCal.get(Calendar.DAY_OF_MONTH)) {
+ age--;
+ }
+ }
+ return age;
+ }
+ public void setAge(int newAge) {
+ if (newAge < MIN_AGE || newAge > MAX_AGE) {
+ throw new IllegalArgumentException(String.valueOf(newAge));
+ }
+
+ int oldAge = this.getAge();
+ int delta = newAge - oldAge;
+
+ Calendar newBirthCal = Calendar.getInstance();
+ newBirthCal.setTimeInMillis(this.birthCal.getTime().getTime());
+ // if the age increased, the birth date must be "decreased"; and vice versa
+ newBirthCal.set(Calendar.YEAR, newBirthCal.get(Calendar.YEAR) - delta);
+ this.setBirthDate(newBirthCal.getTime());
+ }
+ public String getEyeColor() {
+ return this.eyeColor;
+ }
+ public void setEyeColor(String eyeColor) {
+ if ( ! ArrayTools.contains(VALID_EYE_COLORS, eyeColor)) {
+ throw new IllegalArgumentException(eyeColor);
+ }
+ Object old = this.eyeColor;
+ this.eyeColor = eyeColor;
+ this.firePropertyChanged(EYE_COLOR_PROPERTY, old, eyeColor);
+ }
+ @Override
+ public String toString() {
+ return "TestModel(birth: " + this.getBirthDate() + " - eyes: " + this.eyeColor + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterTests.java
new file mode 100644
index 0000000..e1e783e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterTests.java
@@ -0,0 +1,653 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.iterator.CloneIterator;
+import org.eclipse.persistence.tools.utility.iterator.IteratorTools;
+import org.eclipse.persistence.tools.utility.iterator.TransformationIterator;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CollectionAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.TableModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class TableModelAdapterTests extends TestCase {
+ private Crowd crowd;
+ TableModelEvent event;
+
+ public TableModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.crowd = this.buildCrowd();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testGetRowCount() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ assertEquals(0, tableModelAdapter.getRowCount());
+ // we need to add a listener to wake up the adapter
+ tableModelAdapter.addTableModelListener(this.buildTableModelListener());
+ assertEquals(this.crowd.peopleSize(), tableModelAdapter.getRowCount());
+ }
+
+ public void testGetColumnCount() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ assertEquals(PersonColumnAdapter.COLUMN_COUNT, tableModelAdapter.getColumnCount());
+ }
+
+ public void testGetValueAt() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ tableModelAdapter.addTableModelListener(this.buildTableModelListener());
+
+ List<String> sortedNames = this.sortedNames();
+ for (int i = 0; i < this.crowd.peopleSize(); i++) {
+ assertEquals(sortedNames.get(i), tableModelAdapter.getValueAt(i, PersonColumnAdapter.NAME_COLUMN));
+ }
+ }
+
+ public void testSetValueAt() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ this.event = null;
+ tableModelAdapter.addTableModelListener(new TestTableModelListener() {
+ @Override
+ public void tableChanged(TableModelEvent e) {
+ TableModelAdapterTests.this.event = e;
+ }
+ });
+
+ Person person = this.crowd.personNamed("Gollum");
+ assertEquals(Person.EYE_COLOR_BLUE, person.getEyeColor());
+ assertFalse(person.isEvil());
+ assertEquals(0, person.getRank());
+
+ for (int i = 0; i < tableModelAdapter.getRowCount(); i++) {
+ if (tableModelAdapter.getValueAt(i, PersonColumnAdapter.NAME_COLUMN).equals("Gollum")) {
+ tableModelAdapter.setValueAt(Person.EYE_COLOR_HAZEL, i, PersonColumnAdapter.EYE_COLOR_COLUMN);
+ tableModelAdapter.setValueAt(Boolean.TRUE, i, PersonColumnAdapter.EVIL_COLUMN);
+ tableModelAdapter.setValueAt(new Integer(-1), i, PersonColumnAdapter.RANK_COLUMN);
+ break;
+ }
+ }
+ assertNotNull(this.event);
+ assertEquals(Person.EYE_COLOR_HAZEL, person.getEyeColor());
+ assertTrue(person.isEvil());
+ assertEquals(-1, person.getRank());
+ }
+
+ public void testAddRow() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ this.event = null;
+ tableModelAdapter.addTableModelListener(this.buildSingleEventListener());
+ // add a person to the end of the list so we only trigger one event
+ this.crowd.addPerson("Zzzzz");
+ assertNotNull(this.event);
+ assertEquals(TableModelEvent.INSERT, this.event.getType());
+ assertEquals(TableModelEvent.ALL_COLUMNS, this.event.getColumn());
+ }
+
+ public void testRemoveRow() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ this.event = null;
+ tableModelAdapter.addTableModelListener(this.buildSingleEventListener());
+ // removing a person should only trigger one event, since a re-sort is not needed
+ this.crowd.removePerson(this.crowd.personNamed("Gollum"));
+ assertNotNull(this.event);
+ assertEquals(TableModelEvent.DELETE, this.event.getType());
+ assertEquals(TableModelEvent.ALL_COLUMNS, this.event.getColumn());
+ }
+
+ public void testChangeCell() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ this.event = null;
+ tableModelAdapter.addTableModelListener(this.buildSingleEventListener());
+ // add a person to the end of the list so we only trigger one event
+ Person person = this.crowd.personNamed("Gollum");
+ person.setEvil(true);
+ assertNotNull(this.event);
+ assertEquals(TableModelEvent.UPDATE, this.event.getType());
+ assertEquals(PersonColumnAdapter.EVIL_COLUMN, this.event.getColumn());
+ }
+
+ public void testLazyListListener() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ TableModelListener listener = this.buildTableModelListener();
+ assertTrue(this.crowd.hasNoCollectionChangeListeners(Crowd.PEOPLE_COLLECTION));
+ tableModelAdapter.addTableModelListener(listener);
+ assertTrue(this.crowd.hasAnyCollectionChangeListeners(Crowd.PEOPLE_COLLECTION));
+ tableModelAdapter.removeTableModelListener(listener);
+ assertTrue(this.crowd.hasNoCollectionChangeListeners(Crowd.PEOPLE_COLLECTION));
+ }
+
+ public void testLazyCellListener() throws Exception {
+ TableModelAdapter<Person> tableModelAdapter = this.buildTableModelAdapter();
+ TableModelListener listener = this.buildTableModelListener();
+ Person person = this.crowd.personNamed("Gollum");
+ assertTrue(person.hasNoPropertyChangeListeners(Person.NAME_PROPERTY));
+ assertTrue(person.hasNoPropertyChangeListeners(Person.BIRTH_DATE_PROPERTY));
+ assertTrue(person.hasNoPropertyChangeListeners(Person.EYE_COLOR_PROPERTY));
+ assertTrue(person.hasNoPropertyChangeListeners(Person.EVIL_PROPERTY));
+ assertTrue(person.hasNoPropertyChangeListeners(Person.RANK_PROPERTY));
+
+ tableModelAdapter.addTableModelListener(listener);
+ assertTrue(person.hasAnyPropertyChangeListeners(Person.NAME_PROPERTY));
+ assertTrue(person.hasAnyPropertyChangeListeners(Person.BIRTH_DATE_PROPERTY));
+ assertTrue(person.hasAnyPropertyChangeListeners(Person.EYE_COLOR_PROPERTY));
+ assertTrue(person.hasAnyPropertyChangeListeners(Person.EVIL_PROPERTY));
+ assertTrue(person.hasAnyPropertyChangeListeners(Person.RANK_PROPERTY));
+
+ tableModelAdapter.removeTableModelListener(listener);
+ assertTrue(person.hasNoPropertyChangeListeners(Person.NAME_PROPERTY));
+ assertTrue(person.hasNoPropertyChangeListeners(Person.BIRTH_DATE_PROPERTY));
+ assertTrue(person.hasNoPropertyChangeListeners(Person.EYE_COLOR_PROPERTY));
+ assertTrue(person.hasNoPropertyChangeListeners(Person.EVIL_PROPERTY));
+ assertTrue(person.hasNoPropertyChangeListeners(Person.RANK_PROPERTY));
+ }
+
+ private TableModelAdapter<Person> buildTableModelAdapter() {
+ return new TableModelAdapter<Person>(this.buildSortedPeopleAdapter(), this.buildColumnAdapter()) {
+ @Override
+ protected PropertyChangeListener buildCellListener() {
+ return this.buildCellListener_();
+ }
+ @Override
+ protected ListChangeListener buildListChangeListener() {
+ return this.buildListChangeListener_();
+ }
+ };
+ }
+
+ private ListValueModel<Person> buildSortedPeopleAdapter() {
+ return new SortedListValueModelAdapter<Person>(this.buildPeopleAdapter());
+ }
+
+ private CollectionValueModel<Person> buildPeopleAdapter() {
+ return new CollectionAspectAdapter<Crowd, Person>(Crowd.PEOPLE_COLLECTION, this.crowd) {
+ @Override
+ protected Iterator<Person> iterator_() {
+ return this.subject.people();
+ }
+ @Override
+ protected int size_() {
+ return this.subject.peopleSize();
+ }
+ };
+ }
+
+ private Crowd buildCrowd() {
+ Crowd result = new Crowd();
+ result.addPerson("Bilbo");
+ result.addPerson("Gollum");
+ result.addPerson("Frodo");
+ result.addPerson("Samwise");
+ return result;
+ }
+
+ private TableModelAdapter.ColumnAdapter buildColumnAdapter() {
+ return new PersonColumnAdapter();
+ }
+
+ private TableModelListener buildTableModelListener() {
+ return new TestTableModelListener();
+ }
+
+ private List<String> sortedNames() {
+ return new ArrayList<String>(CollectionTools.sortedSet(this.crowd.peopleNames()));
+ }
+
+ private TableModelListener buildSingleEventListener() {
+ return new TestTableModelListener() {
+ @Override
+ public void tableChanged(TableModelEvent e) {
+ // we expect only a single event
+ if (TableModelAdapterTests.this.event == null) {
+ TableModelAdapterTests.this.event = e;
+ } else {
+ fail("unexpected event");
+ }
+ }
+ };
+ }
+
+
+ // ********** classes **********
+
+ public static class PersonColumnAdapter
+ implements TableModelAdapter.ColumnAdapter
+ {
+ public static final int COLUMN_COUNT = 7;
+
+ public static final int NAME_COLUMN = 0;
+ public static final int BIRTH_DATE_COLUMN = 1;
+ public static final int GONE_WEST_DATE_COLUMN = 2;
+ public static final int EYE_COLOR_COLUMN = 3;
+ public static final int EVIL_COLUMN = 4;
+ public static final int RANK_COLUMN = 5;
+ public static final int ADVENTURE_COUNT_COLUMN = 6;
+
+ private static final String[] COLUMN_NAMES = new String[] {
+ "Name",
+ "Birth",
+ "Gone West",
+ "Eyes",
+ "Evil",
+ "Rank",
+ "Adventures"
+ };
+
+
+ @Override
+ public int columnCount() {
+ return COLUMN_COUNT;
+ }
+
+ @Override
+ public String columnName(int index) {
+ return COLUMN_NAMES[index];
+ }
+
+ @Override
+ public Class<?> columnClass(int index) {
+ switch (index) {
+ case NAME_COLUMN: return Object.class;
+ case BIRTH_DATE_COLUMN: return Date.class;
+ case GONE_WEST_DATE_COLUMN: return Date.class;
+ case EYE_COLOR_COLUMN: return Object.class;
+ case EVIL_COLUMN: return Boolean.class;
+ case RANK_COLUMN: return Integer.class;
+ case ADVENTURE_COUNT_COLUMN:return Integer.class;
+ default: return Object.class;
+ }
+ }
+
+ @Override
+ public boolean columnIsEditable(int index) {
+ return index != NAME_COLUMN;
+ }
+
+ @Override
+ public ModifiablePropertyValueModel<Object>[] cellModels(Object subject) {
+ Person person = (Person) subject;
+ @SuppressWarnings("unchecked")
+ ModifiablePropertyValueModel<Object>[] result = new ModifiablePropertyValueModel[COLUMN_COUNT];
+
+ result[NAME_COLUMN] = this.buildNameAdapter(person);
+ result[BIRTH_DATE_COLUMN] = this.buildBirthDateAdapter(person);
+ result[GONE_WEST_DATE_COLUMN] = this.buildGoneWestDateAdapter(person);
+ result[EYE_COLOR_COLUMN] = this.buildEyeColorAdapter(person);
+ result[EVIL_COLUMN] = this.buildEvilAdapter(person);
+ result[RANK_COLUMN] = this.buildRankAdapter(person);
+ result[ADVENTURE_COUNT_COLUMN] = this.buildAdventureCountAdapter(person);
+
+ return result;
+ }
+
+ private ModifiablePropertyValueModel<Object> buildNameAdapter(Person person) {
+ return new PropertyAspectAdapter<Person, Object>(Person.NAME_PROPERTY, person) {
+ @Override
+ protected String buildValue_() {
+ return this.subject.getName();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setName((String) value);
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Object> buildBirthDateAdapter(Person person) {
+ return new PropertyAspectAdapter<Person, Object>(Person.BIRTH_DATE_PROPERTY, person) {
+ @Override
+ protected Date buildValue_() {
+ return this.subject.getBirthDate();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setBirthDate((Date) value);
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Object> buildGoneWestDateAdapter(Person person) {
+ return new PropertyAspectAdapter<Person, Object>(Person.GONE_WEST_DATE_PROPERTY, person) {
+ @Override
+ protected Date buildValue_() {
+ return this.subject.getGoneWestDate();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setGoneWestDate((Date) value);
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Object> buildEyeColorAdapter(Person person) {
+ return new PropertyAspectAdapter<Person, Object>(Person.EYE_COLOR_PROPERTY, person) {
+ @Override
+ protected String buildValue_() {
+ return this.subject.getEyeColor();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setEyeColor((String) value);
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Object> buildEvilAdapter(Person person) {
+ return new PropertyAspectAdapter<Person, Object>(Person.EVIL_PROPERTY, person) {
+ @Override
+ protected Boolean buildValue_() {
+ return Boolean.valueOf(this.subject.isEvil());
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setEvil(((Boolean)value).booleanValue());
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Object> buildRankAdapter(Person person) {
+ return new PropertyAspectAdapter<Person, Object>(Person.RANK_PROPERTY, person) {
+ @Override
+ protected Integer buildValue_() {
+ return new Integer(this.subject.getRank());
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setRank(((Integer) value).intValue());
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Object> buildAdventureCountAdapter(Person person) {
+ return new PropertyAspectAdapter<Person, Object>(Person.ADVENTURE_COUNT_PROPERTY, person) {
+ @Override
+ protected Integer buildValue_() {
+ return new Integer(this.subject.getAdventureCount());
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setAdventureCount(((Integer) value).intValue());
+ }
+ };
+ }
+
+ }
+
+
+ public static class Crowd extends AbstractModel {
+ private final Collection<Person> people;
+ public static final String PEOPLE_COLLECTION = "people";
+
+ public Crowd() {
+ super();
+ this.people = new ArrayList<Person>();
+ }
+
+
+ public Iterator<Person> people() {
+ return new CloneIterator<Person>(this.people, new CloneIterator.Remover<Person>() {
+ @Override
+ public void remove(Person person) {
+ Crowd.this.removePerson(person);
+ }
+ });
+ }
+
+ public int peopleSize() {
+ return this.people.size();
+ }
+
+ public Person addPerson(String name) {
+ this.checkPersonName(name);
+ return this.addPerson(new Person(this, name));
+ }
+
+ private Person addPerson(Person person) {
+ this.addItemToCollection(person, this.people, PEOPLE_COLLECTION);
+ return person;
+ }
+
+ public void removePerson(Person person) {
+ this.removeItemFromCollection(person, this.people, PEOPLE_COLLECTION);
+ }
+
+ public void removePeople(Collection<Person> persons) {
+ this.removeItemsFromCollection(persons, this.people, PEOPLE_COLLECTION);
+ }
+
+ public void removePeople(Iterator<Person> persons) {
+ this.removeItemsFromCollection(persons, this.people, PEOPLE_COLLECTION);
+ }
+
+ void checkPersonName(String personName) {
+ if (personName == null) {
+ throw new NullPointerException();
+ }
+ if (IteratorTools.contains(this.peopleNames(), personName)) {
+ throw new IllegalArgumentException(personName);
+ }
+ }
+
+ public Iterator<String> peopleNames() {
+ return new TransformationIterator<Person, String>(this.people.iterator()) {
+ @Override
+ protected String transform(Person person) {
+ return person.getName();
+ }
+ };
+ }
+
+ public Person personNamed(String name) {
+ for (Iterator<Person> stream = this.people.iterator(); stream.hasNext(); ) {
+ Person person = stream.next();
+ if (person.getName().equals(name)) {
+ return person;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, String.valueOf(this.people.size()) + " people");
+ }
+
+ }
+
+
+ public static class Person extends AbstractModel implements Comparable<Person> {
+ private Crowd crowd;
+ private String name;
+ public static final String NAME_PROPERTY= "name";
+ private Date birthDate;
+ public static final String BIRTH_DATE_PROPERTY= "birthDate";
+ private Date goneWestDate;
+ public static final String GONE_WEST_DATE_PROPERTY= "goneWestDate";
+ private String eyeColor;
+ public static final String EYE_COLOR_PROPERTY= "eyeColor";
+ public static final String EYE_COLOR_BLUE = "blue";
+ public static final String EYE_COLOR_GREEN = "green";
+ public static final String EYE_COLOR_BROWN = "brown";
+ public static final String EYE_COLOR_HAZEL = "hazel";
+ public static final String EYE_COLOR_PINK = "pink";
+ private static Collection<String> validEyeColors;
+ public static final String DEFAULT_EYE_COLOR = EYE_COLOR_BLUE;
+ private boolean evil;
+ public static final String EVIL_PROPERTY= "evil";
+ private int rank;
+ public static final String RANK_PROPERTY= "rank";
+ private int adventureCount;
+ public static final String ADVENTURE_COUNT_PROPERTY= "adventureCount";
+
+ Person(Crowd crowd, String name) {
+ super();
+ this.crowd = crowd;
+ this.name = name;
+ this.birthDate = new Date();
+ Calendar c = Calendar.getInstance();
+ c.add(Calendar.YEAR, 250);
+ this.goneWestDate = new Date(c.getTimeInMillis());
+ this.eyeColor = DEFAULT_EYE_COLOR;
+ this.evil = false;
+ this.rank = 0;
+ this.adventureCount = 0;
+ }
+
+ public static Collection<String> getValidEyeColors() {
+ if (validEyeColors == null) {
+ validEyeColors = buildValidEyeColors();
+ }
+ return validEyeColors;
+ }
+
+ private static Collection<String> buildValidEyeColors() {
+ Collection<String> result = new ArrayList<String>();
+ result.add(EYE_COLOR_BLUE);
+ result.add(EYE_COLOR_GREEN);
+ result.add(EYE_COLOR_BROWN);
+ result.add(EYE_COLOR_HAZEL);
+ result.add(EYE_COLOR_PINK);
+ return result;
+ }
+
+ public Crowd getCrowd() {
+ return this.crowd;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+ public void setName(String name) {
+ this.crowd.checkPersonName(name);
+ Object old = this.name;
+ this.name = name;
+ this.firePropertyChanged(NAME_PROPERTY, old, name);
+ }
+
+ public Date getBirthDate() {
+ return this.birthDate;
+ }
+ public void setBirthDate(Date birthDate) {
+ Object old = this.birthDate;
+ this.birthDate = birthDate;
+ this.firePropertyChanged(BIRTH_DATE_PROPERTY, old, birthDate);
+ }
+
+ public Date getGoneWestDate() {
+ return this.goneWestDate;
+ }
+ public void setGoneWestDate(Date goneWestDate) {
+ Object old = this.goneWestDate;
+ this.goneWestDate = goneWestDate;
+ this.firePropertyChanged(GONE_WEST_DATE_PROPERTY, old, goneWestDate);
+ }
+
+ public String getEyeColor() {
+ return this.eyeColor;
+ }
+ public void setEyeColor(String eyeColor) {
+ if (! getValidEyeColors().contains(eyeColor)) {
+ throw new IllegalArgumentException(eyeColor);
+ }
+ Object old = this.eyeColor;
+ this.eyeColor = eyeColor;
+ this.firePropertyChanged(EYE_COLOR_PROPERTY, old, eyeColor);
+ }
+
+ public boolean isEvil() {
+ return this.evil;
+ }
+ public void setEvil(boolean evil) {
+ boolean old = this.evil;
+ this.evil = evil;
+ this.firePropertyChanged(EVIL_PROPERTY, old, evil);
+ }
+
+ public int getRank() {
+ return this.rank;
+ }
+ public void setRank(int rank) {
+ int old = this.rank;
+ this.rank = rank;
+ this.firePropertyChanged(RANK_PROPERTY, old, rank);
+ }
+
+ public int getAdventureCount() {
+ return this.adventureCount;
+ }
+ public void setAdventureCount(int adventureCount) {
+ int old = this.adventureCount;
+ this.adventureCount = adventureCount;
+ this.firePropertyChanged(ADVENTURE_COUNT_PROPERTY, old, adventureCount);
+ }
+
+ @Override
+ public int compareTo(Person p) {
+ return this.name.compareToIgnoreCase(p.name);
+ }
+
+ @Override
+ public String toString() {
+ return this.name +
+ "\tborn: " + DateFormat.getDateInstance().format(this.birthDate) +
+ "\tgone west: " + DateFormat.getDateInstance().format(this.goneWestDate) +
+ "\teyes: " + this.eyeColor +
+ "\tevil: " + this.evil +
+ "\trank: " + this.rank +
+ "\tadventures: " + this.adventureCount
+ ;
+ }
+
+ }
+
+
+ private class TestTableModelListener implements TableModelListener {
+ TestTableModelListener() {
+ super();
+ }
+ @Override
+ public void tableChanged(TableModelEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterUITest.java
new file mode 100644
index 0000000..41ee4a9
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterUITest.java
@@ -0,0 +1,740 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ButtonModel;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.SpinnerModel;
+import javax.swing.UIManager;
+import javax.swing.WindowConstants;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+import javax.swing.text.Document;
+import org.eclipse.persistence.tools.utility.iterator.IteratorTools;
+import org.eclipse.persistence.tools.utility.model.value.CollectionAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemPropertyListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.swing.CheckBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.ComboBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.DateSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.DocumentAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.NumberSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.ObjectListSelectionModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.TableModelAdapter;
+import org.eclipse.persistence.tools.utility.swing.CheckBoxTableCellRenderer;
+import org.eclipse.persistence.tools.utility.swing.ComboBoxTableCellRenderer;
+import org.eclipse.persistence.tools.utility.swing.SpinnerTableCellRenderer;
+import org.eclipse.persistence.tools.utility.swing.TableCellEditorAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TableModelAdapterTests.Crowd;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TableModelAdapterTests.Person;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TableModelAdapterTests.PersonColumnAdapter;
+
+/**
+ * an example UI for testing the TableModelAdapter
+ * "name" column is read-only text field
+ * "birth date" column is date text field
+ * "gone west date" column is date spinner
+ * "eye color" column is combo-box
+ * "evil" column is check box
+ * "rank" column is number text field
+ * "adventure count" column is number spinner
+ *
+ * Note that the table model and row selection model share the same
+ * list value model (the sorted people adapter)
+ */
+@SuppressWarnings("nls")
+public class TableModelAdapterUITest {
+ private SimpleCollectionValueModel<Object> eyeColorsHolder; // Object because it adapts to a combo-box
+ private ModifiablePropertyValueModel<Crowd> crowdHolder;
+ private ModifiablePropertyValueModel<Person> selectedPersonHolder;
+ private ListValueModel<Person> sortedPeopleAdapter;
+ private TableModel tableModel;
+ private ObjectListSelectionModel rowSelectionModel;
+ private Action removeAction;
+ private Action renameAction;
+
+ public static void main(String[] args) throws Exception {
+ new TableModelAdapterUITest().exec(args);
+ }
+
+ protected TableModelAdapterUITest() {
+ super();
+ }
+
+ protected void exec(@SuppressWarnings("unused") String[] args) throws Exception {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ this.eyeColorsHolder = this. buildEyeColorCollectionHolder();
+ this.crowdHolder = this.buildCrowdHolder();
+ this.selectedPersonHolder = this.buildSelectedPersonHolder();
+ this.sortedPeopleAdapter = this.buildSortedPeopleAdapter();
+ this.tableModel = this.buildTableModel();
+ this.rowSelectionModel = this.buildRowSelectionModel();
+ this.openWindow();
+ }
+
+ private SimpleCollectionValueModel<Object> buildEyeColorCollectionHolder() {
+ return new SimpleCollectionValueModel<Object>(new ArrayList<Object>(Person.getValidEyeColors()));
+ }
+
+ private ModifiablePropertyValueModel<Crowd> buildCrowdHolder() {
+ return new SimplePropertyValueModel<Crowd>(this.buildCrowd());
+ }
+
+ private Crowd buildCrowd() {
+ Crowd crowd = new Crowd();
+
+ Person p = crowd.addPerson("Bilbo");
+ p.setEyeColor(Person.EYE_COLOR_BROWN);
+ p.setRank(22);
+ p.setAdventureCount(1);
+
+ p = crowd.addPerson("Gollum");
+ p.setEyeColor(Person.EYE_COLOR_PINK);
+ p.setEvil(true);
+ p.setRank(2);
+ p.setAdventureCount(50);
+
+ p = crowd.addPerson("Frodo");
+ p.setEyeColor(Person.EYE_COLOR_BLUE);
+ p.setRank(34);
+ p.setAdventureCount(1);
+
+ p = crowd.addPerson("Samwise");
+ p.setEyeColor(Person.EYE_COLOR_GREEN);
+ p.setRank(19);
+ p.setAdventureCount(1);
+
+ return crowd;
+ }
+
+ private ModifiablePropertyValueModel<Person> buildSelectedPersonHolder() {
+ return new SimplePropertyValueModel<Person>();
+ }
+
+ private ListValueModel<Person> buildSortedPeopleAdapter() {
+ return new SortedListValueModelWrapper<Person>(this.buildPeopleNameAdapter());
+ }
+
+ // the list will need to be re-sorted if a name changes
+ private ListValueModel<Person> buildPeopleNameAdapter() {
+ return new ItemPropertyListValueModelAdapter<Person>(this.buildPeopleAdapter(), Person.NAME_PROPERTY);
+ }
+
+ private CollectionValueModel<Person> buildPeopleAdapter() {
+ return new CollectionAspectAdapter<Crowd, Person>(this.crowdHolder, Crowd.PEOPLE_COLLECTION) {
+ @Override
+ protected Iterator<Person> iterator_() {
+ return this.subject.people();
+ }
+ @Override
+ protected int size_() {
+ return this.subject.peopleSize();
+ }
+ };
+ }
+
+ private TableModel buildTableModel() {
+ return new TableModelAdapter<Person>(this.sortedPeopleAdapter, this.buildColumnAdapter());
+ }
+
+ protected TableModelAdapter.ColumnAdapter buildColumnAdapter() {
+ return new PersonColumnAdapter();
+ }
+
+ private ObjectListSelectionModel buildRowSelectionModel() {
+ ObjectListSelectionModel rsm = new ObjectListSelectionModel(new ListModelAdapter(this.sortedPeopleAdapter));
+ rsm.addListSelectionListener(this.buildRowSelectionListener());
+ rsm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ return rsm;
+ }
+
+ private ListSelectionListener buildRowSelectionListener() {
+ return new ListSelectionListener() {
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ if (e.getValueIsAdjusting()) {
+ return;
+ }
+ TableModelAdapterUITest.this.rowSelectionChanged(e);
+ }
+ };
+ }
+
+ void rowSelectionChanged(@SuppressWarnings("unused") ListSelectionEvent event) {
+ Person selection = (Person) this.rowSelectionModel.selectedValue();
+ this.selectedPersonHolder.setValue(selection);
+ boolean personSelected = (selection != null);
+ this.removeAction.setEnabled(personSelected);
+ this.renameAction.setEnabled(personSelected);
+ }
+
+ private void openWindow() {
+ JFrame window = new JFrame(this.getClass().getSimpleName());
+ window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ window.addWindowListener(this.buildWindowListener());
+ window.getContentPane().add(this.buildMainPanel(), "Center");
+ window.setLocation(200, 200);
+ window.setSize(600, 400);
+ window.setVisible(true);
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private Component buildMainPanel() {
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(this.buildTablePane(), BorderLayout.CENTER);
+ mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ private Component buildTablePane() {
+ return new JScrollPane(this.buildTable());
+ }
+
+ private JTable buildTable() {
+ JTable table = new JTable(this.tableModel);
+ table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); // see Java bug 5007652
+ table.setSelectionModel(this.rowSelectionModel);
+ table.setDoubleBuffered(true);
+ table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
+ int rowHeight = 20; // start with minimum of 20
+
+ // gone west column (spinner)
+ TableColumn column = table.getColumnModel().getColumn(PersonColumnAdapter.GONE_WEST_DATE_COLUMN);
+ SpinnerTableCellRenderer spinnerRenderer = this.buildDateSpinnerRenderer();
+ column.setCellRenderer(spinnerRenderer);
+ column.setCellEditor(new TableCellEditorAdapter(this.buildDateSpinnerRenderer()));
+ rowHeight = Math.max(rowHeight, spinnerRenderer.preferredHeight());
+
+ // eye color column (combo-box)
+ // the jdk combo-box renderer looks like a text field
+ // until the user starts an edit - use a custom one
+ column = table.getColumnModel().getColumn(PersonColumnAdapter.EYE_COLOR_COLUMN);
+ ComboBoxTableCellRenderer eyeColorRenderer = this.buildEyeColorComboBoxRenderer();
+ column.setCellRenderer(eyeColorRenderer);
+ column.setCellEditor(new TableCellEditorAdapter(this.buildEyeColorComboBoxRenderer()));
+ rowHeight = Math.max(rowHeight, eyeColorRenderer.preferredHeight());
+
+ // evil (check box)
+ // the jdk check box renderer and editor suck - use a custom ones
+ column = table.getColumnModel().getColumn(PersonColumnAdapter.EVIL_COLUMN);
+ CheckBoxTableCellRenderer evilRenderer = new CheckBoxTableCellRenderer();
+ column.setCellRenderer(evilRenderer);
+ column.setCellEditor(new TableCellEditorAdapter(new CheckBoxTableCellRenderer()));
+ rowHeight = Math.max(rowHeight, evilRenderer.preferredHeight());
+
+ // adventure count column (spinner)
+ column = table.getColumnModel().getColumn(PersonColumnAdapter.ADVENTURE_COUNT_COLUMN);
+ spinnerRenderer = this.buildNumberSpinnerRenderer();
+ column.setCellRenderer(spinnerRenderer);
+ column.setCellEditor(new TableCellEditorAdapter(this.buildNumberSpinnerRenderer()));
+ rowHeight = Math.max(rowHeight, spinnerRenderer.preferredHeight());
+
+ table.setRowHeight(rowHeight);
+ return table;
+ }
+
+ private SpinnerTableCellRenderer buildDateSpinnerRenderer() {
+ return new SpinnerTableCellRenderer(new DateSpinnerModelAdapter(new SimplePropertyValueModel<Object>()));
+ }
+
+ private SpinnerTableCellRenderer buildNumberSpinnerRenderer() {
+ return new SpinnerTableCellRenderer(new NumberSpinnerModelAdapter(new SimplePropertyValueModel<Number>()));
+ }
+
+ private ComboBoxTableCellRenderer buildEyeColorComboBoxRenderer() {
+ return new ComboBoxTableCellRenderer(this.buildReadOnlyEyeColorComboBoxModel(), this.buildEyeColorRenderer());
+ }
+
+ private ComboBoxModel buildReadOnlyEyeColorComboBoxModel() {
+ return new ComboBoxModelAdapter(this.eyeColorsHolder, new SimplePropertyValueModel<Object>());
+ }
+
+ private ListCellRenderer buildEyeColorRenderer() {
+ return new EyeColorRenderer();
+ }
+
+ private Component buildControlPanel() {
+ JPanel controlPanel = new JPanel(new GridLayout(0, 1));
+ controlPanel.add(this.buildButtonPanel());
+ controlPanel.add(this.buildPersonPanel());
+ return controlPanel;
+ }
+
+ private Component buildButtonPanel() {
+ JPanel buttonPanel = new JPanel(new GridLayout(1, 0));
+ buttonPanel.add(this.buildAddButton());
+ buttonPanel.add(this.buildRemoveButton());
+ buttonPanel.add(this.buildRenameButton());
+ buttonPanel.add(this.buildAddEyeColorButton());
+ buttonPanel.add(this.buildPrintButton());
+ buttonPanel.add(this.buildResetButton());
+ return buttonPanel;
+ }
+
+ private Component buildPersonPanel() {
+ JPanel personPanel = new JPanel(new GridLayout(1, 0));
+ personPanel.add(this.buildNameTextField());
+ personPanel.add(this.buildBirthDateSpinner());
+ personPanel.add(this.buildGoneWestDateSpinner());
+ personPanel.add(this.buildEyeColorComboBox());
+ personPanel.add(this.buildEvilCheckBox());
+ personPanel.add(this.buildRankSpinner());
+ personPanel.add(this.buildAdventureCountSpinner());
+ return personPanel;
+ }
+
+
+ // ********** add button **********
+
+ private JButton buildAddButton() {
+ return new JButton(this.buildAddAction());
+ }
+
+ private Action buildAddAction() {
+ Action action = new AbstractAction("add") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TableModelAdapterUITest.this.addPerson();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void addPerson() {
+ String name = this.getNameFromUser();
+ if (name != null) {
+ this.setSelectedPerson(this.crowd().addPerson(name));
+ }
+ }
+
+
+ // ********** remove button **********
+
+ private JButton buildRemoveButton() {
+ return new JButton(this.buildRemoveAction());
+ }
+
+ private Action buildRemoveAction() {
+ this.removeAction = new AbstractAction("remove") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TableModelAdapterUITest.this.removePerson();
+ }
+ };
+ this.removeAction.setEnabled(false);
+ return this.removeAction;
+ }
+
+ void removePerson() {
+ Person person = this.selectedPerson();
+ if (person != null) {
+ this.crowd().removePerson(person);
+ }
+ }
+
+
+ // ********** rename button **********
+
+ private JButton buildRenameButton() {
+ return new JButton(this.buildRenameAction());
+ }
+
+ private Action buildRenameAction() {
+ this.renameAction = new AbstractAction("rename") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TableModelAdapterUITest.this.renamePerson();
+ }
+ };
+ this.renameAction.setEnabled(false);
+ return this.renameAction;
+ }
+
+ void renamePerson() {
+ Person person = this.selectedPerson();
+ if (person != null) {
+ String name = this.promptUserForName(person.getName());
+ if (name != null) {
+ person.setName(name);
+ this.setSelectedPerson(person);
+ }
+ }
+ }
+
+
+ // ********** add eye color button **********
+
+ private JButton buildAddEyeColorButton() {
+ return new JButton(this.buildAddEyeColorAction());
+ }
+
+ private Action buildAddEyeColorAction() {
+ Action action = new AbstractAction("add eye color") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TableModelAdapterUITest.this.addEyeColor();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void addEyeColor() {
+ String color = this.promptUserForEyeColor();
+ if (color != null) {
+ this.eyeColorsHolder.add(color);
+ }
+ }
+
+ private String promptUserForEyeColor() {
+ while (true) {
+ String eyeColor = JOptionPane.showInputDialog("Eye Color");
+ if (eyeColor == null) {
+ return null; // user pressed <Cancel>
+ }
+ if ((eyeColor.length() == 0)) {
+ JOptionPane.showMessageDialog(null, "The eye color is required.", "Invalid Eye Color", JOptionPane.ERROR_MESSAGE);
+ } else if (IteratorTools.contains(this.eyeColorsHolder.iterator(), eyeColor)) {
+ JOptionPane.showMessageDialog(null, "The eye color already exists.", "Invalid Eye Color", JOptionPane.ERROR_MESSAGE);
+ } else {
+ return eyeColor;
+ }
+ }
+ }
+
+
+ // ********** print button **********
+
+ private JButton buildPrintButton() {
+ return new JButton(this.buildPrintAction());
+ }
+
+ private Action buildPrintAction() {
+ Action action = new AbstractAction("print") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TableModelAdapterUITest.this.printCrowd();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void printCrowd() {
+ System.out.println(this.crowd());
+ for (Iterator<Person> stream = this.crowd().people(); stream.hasNext(); ) {
+ System.out.println("\t" + stream.next());
+ }
+ }
+
+
+ // ********** reset button **********
+
+ private JButton buildResetButton() {
+ return new JButton(this.buildResetAction());
+ }
+
+ private Action buildResetAction() {
+ Action action = new AbstractAction("reset") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TableModelAdapterUITest.this.reset();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ void reset() {
+ this.crowdHolder.setValue(this.buildCrowd());
+ }
+
+
+ // ********** new name dialog **********
+
+ private String getNameFromUser() {
+ return this.promptUserForName(null);
+ }
+
+ private String promptUserForName(@SuppressWarnings("unused") String originalName) {
+ while (true) {
+ String name = JOptionPane.showInputDialog("Person Name");
+ if (name == null) {
+ return null; // user pressed <Cancel>
+ }
+ if ((name.length() == 0)) {
+ JOptionPane.showMessageDialog(null, "The name is required.", "Invalid Name", JOptionPane.ERROR_MESSAGE);
+ } else if (IteratorTools.contains(this.crowd().peopleNames(), name)) {
+ JOptionPane.showMessageDialog(null, "The name already exists.", "Invalid Name", JOptionPane.ERROR_MESSAGE);
+ } else {
+ return name;
+ }
+ }
+ }
+
+
+ // ********** name text field **********
+
+ private Component buildNameTextField() {
+ JTextField textField = new JTextField(this.buildNameDocument(), null, 0);
+ textField.setEditable(false);
+ return textField;
+ }
+
+ private Document buildNameDocument() {
+ return new DocumentAdapter(this.buildNameAdapter());
+ }
+
+ private ModifiablePropertyValueModel<String> buildNameAdapter() {
+ return new PropertyAspectAdapter<Person, String>(this.selectedPersonHolder, Person.NAME_PROPERTY) {
+ @Override
+ protected String buildValue_() {
+ return this.subject.getName();
+ }
+ @Override
+ protected void setValue_(String value) {
+ this.subject.setName(value);
+ }
+ };
+ }
+
+
+ // ********** birth date spinner **********
+
+ private JSpinner buildBirthDateSpinner() {
+ return new JSpinner(this.buildBirthDateSpinnerModel());
+ }
+
+ private SpinnerModel buildBirthDateSpinnerModel() {
+ return new DateSpinnerModelAdapter(this.buildBirthDateAdapter());
+ }
+
+ private ModifiablePropertyValueModel<Object> buildBirthDateAdapter() {
+ return new PropertyAspectAdapter<Person, Object>(this.selectedPersonHolder, Person.BIRTH_DATE_PROPERTY) {
+ @Override
+ protected Date buildValue_() {
+ return this.subject.getBirthDate();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setBirthDate((Date) value);
+ }
+ };
+ }
+
+
+ // ********** gone west date spinner **********
+
+ private JSpinner buildGoneWestDateSpinner() {
+ return new JSpinner(this.buildGoneWestDateSpinnerModel());
+ }
+
+ private SpinnerModel buildGoneWestDateSpinnerModel() {
+ return new DateSpinnerModelAdapter(this.buildGoneWestDateAdapter());
+ }
+
+ private ModifiablePropertyValueModel<Object> buildGoneWestDateAdapter() {
+ return new PropertyAspectAdapter<Person, Object>(this.selectedPersonHolder, Person.GONE_WEST_DATE_PROPERTY) {
+ @Override
+ protected Date buildValue_() {
+ return this.subject.getGoneWestDate();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setGoneWestDate((Date) value);
+ }
+ };
+ }
+
+
+ // ********** eye color combo-box **********
+
+ private JComboBox buildEyeColorComboBox() {
+ return new JComboBox(this.buildEyeColorComboBoxModel());
+ }
+
+ private ComboBoxModel buildEyeColorComboBoxModel() {
+ return new ComboBoxModelAdapter(this.eyeColorsHolder, this.buildEyeColorAdapter());
+ }
+
+ private ModifiablePropertyValueModel<Object> buildEyeColorAdapter() {
+ return new PropertyAspectAdapter<Person, Object>(this.selectedPersonHolder, Person.EYE_COLOR_PROPERTY) {
+ @Override
+ protected Object buildValue_() {
+ return this.subject.getEyeColor();
+ }
+ @Override
+ protected void setValue_(Object value) {
+ this.subject.setEyeColor((String) value);
+ }
+ };
+ }
+
+
+ // ********** evil check box **********
+
+ private JCheckBox buildEvilCheckBox() {
+ JCheckBox checkBox = new JCheckBox();
+ checkBox.setText("evil");
+ checkBox.setModel(this.buildEvilCheckBoxModel());
+ return checkBox;
+ }
+
+ private ButtonModel buildEvilCheckBoxModel() {
+ return new CheckBoxModelAdapter(this.buildEvilAdapter());
+ }
+
+ private ModifiablePropertyValueModel<Boolean> buildEvilAdapter() {
+ return new PropertyAspectAdapter<Person, Boolean>(this.selectedPersonHolder, Person.EVIL_PROPERTY) {
+ @Override
+ protected Boolean buildValue_() {
+ return Boolean.valueOf(this.subject.isEvil());
+ }
+ @Override
+ protected void setValue_(Boolean value) {
+ this.subject.setEvil(value.booleanValue());
+ }
+ };
+ }
+
+
+ // ********** rank spinner **********
+
+ private JSpinner buildRankSpinner() {
+ return new JSpinner(this.buildRankSpinnerModel());
+ }
+
+ private SpinnerModel buildRankSpinnerModel() {
+ return new NumberSpinnerModelAdapter(this.buildRankAdapter());
+ }
+
+ private ModifiablePropertyValueModel<Number> buildRankAdapter() {
+ return new PropertyAspectAdapter<Person, Number>(this.selectedPersonHolder, Person.RANK_PROPERTY) {
+ @Override
+ protected Number buildValue_() {
+ return new Integer(this.subject.getRank());
+ }
+ @Override
+ protected void setValue_(Number value) {
+ this.subject.setRank(value.intValue());
+ }
+ };
+ }
+
+
+ // ********** adventure count spinner **********
+
+ private JSpinner buildAdventureCountSpinner() {
+ return new JSpinner(this.buildAdventureCountSpinnerModel());
+ }
+
+ private SpinnerModel buildAdventureCountSpinnerModel() {
+ return new NumberSpinnerModelAdapter(this.buildAdventureCountAdapter());
+ }
+
+ private ModifiablePropertyValueModel<Number> buildAdventureCountAdapter() {
+ return new PropertyAspectAdapter<Person, Number>(this.selectedPersonHolder, Person.ADVENTURE_COUNT_PROPERTY) {
+ @Override
+ protected Number buildValue_() {
+ return new Integer(this.subject.getAdventureCount());
+ }
+ @Override
+ protected void setValue_(Number value) {
+ this.subject.setAdventureCount(value.intValue());
+ }
+ };
+ }
+
+
+ // ********** queries **********
+
+ private Crowd crowd() {
+ return this.crowdHolder.getValue();
+ }
+
+ private Person selectedPerson() {
+ if (this.rowSelectionModel.isSelectionEmpty()) {
+ return null;
+ }
+ return (Person) this.rowSelectionModel.selectedValue();
+ }
+
+ private void setSelectedPerson(Person person) {
+ this.rowSelectionModel.setSelectedValue(person);
+ }
+
+
+ // ********** custom renderer **********
+
+ /**
+ * This is simply an example of a renderer for the embedded combo-box.
+ * It does nothing special unless you uncomment the code below....
+ */
+ private class EyeColorRenderer extends DefaultListCellRenderer {
+ EyeColorRenderer() {
+ super();
+ }
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ // just do something to show the renderer is working...
+ // value = ">" + value;
+ return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterTests.java
new file mode 100644
index 0000000..5afbbd4
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterTests.java
@@ -0,0 +1,831 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import javax.swing.Icon;
+import javax.swing.JTree;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreeModel;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.io.IndentingPrintWriter;
+import org.eclipse.persistence.tools.utility.iterator.ReadOnlyIterator;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.StateChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.AbstractTreeNodeValueModel;
+import org.eclipse.persistence.tools.utility.model.value.CollectionAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemPropertyListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.NullListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.StaticPropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TransformationListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TreeNodeValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.TreeModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+@SuppressWarnings("nls")
+public class TreeModelAdapterTests extends TestCase {
+ boolean eventFired;
+
+ public TreeModelAdapterTests(String name) {
+ super(name);
+ }
+
+ public void testGetRoot() {
+ TreeModel treeModel = this.buildSortedTreeModel();
+ treeModel.addTreeModelListener(new TestTreeModelListener());
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+ TestModel root = rootNode.getTestModel();
+ assertEquals("root", root.getName());
+// root.dump();
+// rootNode.dump();
+ }
+
+ public void testGetChild() {
+ TreeModel treeModel = this.buildSortedTreeModel();
+ treeModel.addTreeModelListener(new TestTreeModelListener());
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+
+ TestNode expected = rootNode.childNamed("node 1");
+ TestNode actual = (TestNode) treeModel.getChild(rootNode, 1);
+ assertEquals(expected, actual);
+
+ expected = rootNode.childNamed("node 2");
+ actual = (TestNode) treeModel.getChild(rootNode, 2);
+ assertEquals(expected, actual);
+ }
+
+ public void testGetChildCount() {
+ TreeModel treeModel = this.buildSortedTreeModel();
+ treeModel.addTreeModelListener(new TestTreeModelListener());
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+
+ assertEquals(5, treeModel.getChildCount(rootNode));
+
+ TestNode node = rootNode.childNamed("node 1");
+ assertEquals(1, treeModel.getChildCount(node));
+ }
+
+ public void testGetIndexOfChild() {
+ TreeModel treeModel = this.buildSortedTreeModel();
+ treeModel.addTreeModelListener(new TestTreeModelListener());
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+
+ TestNode child = rootNode.childNamed("node 0");
+ assertEquals(0, treeModel.getIndexOfChild(rootNode, child));
+
+ child = rootNode.childNamed("node 1");
+ assertEquals(1, treeModel.getIndexOfChild(rootNode, child));
+
+ child = rootNode.childNamed("node 2");
+ assertEquals(2, treeModel.getIndexOfChild(rootNode, child));
+ TestNode grandchild = child.childNamed("node 2.2");
+ assertEquals(2, treeModel.getIndexOfChild(child, grandchild));
+ }
+
+ public void testIsLeaf() {
+ TreeModel treeModel = this.buildSortedTreeModel();
+ treeModel.addTreeModelListener(new TestTreeModelListener());
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+ assertFalse(treeModel.isLeaf(rootNode));
+ TestNode node = rootNode.childNamed("node 1");
+ assertFalse(treeModel.isLeaf(node));
+ node = rootNode.childNamed("node 3");
+ assertTrue(treeModel.isLeaf(node));
+ }
+
+
+ public void testTreeNodesChanged() {
+ // the only way to trigger a "node changed" event is to use an unsorted tree;
+ // a sorted tree will will trigger only "node removed" and "node inserted" events
+ TreeModel treeModel = this.buildUnsortedTreeModel();
+ this.eventFired = false;
+ treeModel.addTreeModelListener(new TestTreeModelListener() {
+ @Override
+ public void treeNodesChanged(TreeModelEvent e) {
+ TreeModelAdapterTests.this.eventFired = true;
+ }
+ });
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+ TestNode node = rootNode.childNamed("node 1");
+ TestModel tm = node.getTestModel();
+ tm.setName("node 1++");
+ assertTrue(this.eventFired);
+
+ this.eventFired = false;
+ node = node.childNamed("node 1.1");
+ tm = node.getTestModel();
+ tm.setName("node 1.1++");
+ assertTrue(this.eventFired);
+ }
+
+ public void testTreeNodesInserted() {
+ // use an unsorted tree so the nodes are not re-shuffled...
+ TreeModel treeModel = this.buildUnsortedTreeModel();
+ this.eventFired = false;
+ treeModel.addTreeModelListener(new TestTreeModelListener() {
+ @Override
+ public void treeNodesInserted(TreeModelEvent e) {
+ TreeModelAdapterTests.this.eventFired = true;
+ }
+ });
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+ TestNode node = rootNode.childNamed("node 1");
+ TestModel tm = node.getTestModel();
+ tm.addChild("new child...");
+ assertTrue(this.eventFired);
+
+ this.eventFired = false;
+ node = node.childNamed("node 1.1");
+ tm = node.getTestModel();
+ tm.addChild("another new child...");
+ assertTrue(this.eventFired);
+ }
+
+ public void testTreeNodesRemoved() {
+ TreeModel treeModel = this.buildUnsortedTreeModel();
+ this.eventFired = false;
+ treeModel.addTreeModelListener(new TestTreeModelListener() {
+ @Override
+ public void treeNodesRemoved(TreeModelEvent e) {
+ TreeModelAdapterTests.this.eventFired = true;
+ }
+ });
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+ TestModel root = rootNode.getTestModel();
+ root.removeChild(root.childNamed("node 3"));
+ assertTrue(this.eventFired);
+
+ this.eventFired = false;
+ TestNode node = rootNode.childNamed("node 2");
+ TestModel tm = node.getTestModel();
+ tm.removeChild(tm.childNamed("node 2.2"));
+ assertTrue(this.eventFired);
+ }
+
+ public void testTreeStructureChanged() {
+ ModifiablePropertyValueModel<TreeNodeValueModel<Object>> nodeHolder = new SimplePropertyValueModel<TreeNodeValueModel<Object>>(this.buildSortedRootNode());
+ TreeModel treeModel = this.buildTreeModel(nodeHolder);
+ this.eventFired = false;
+ treeModel.addTreeModelListener(new TestTreeModelListener() {
+ @Override
+ public void treeNodesInserted(TreeModelEvent e) {
+ // do nothing
+ }
+ @Override
+ public void treeNodesRemoved(TreeModelEvent e) {
+ // do nothing
+ }
+ @Override
+ public void treeStructureChanged(TreeModelEvent e) {
+ TreeModelAdapterTests.this.eventFired = true;
+ }
+ });
+ nodeHolder.setValue(this.buildUnsortedRootNode());
+ assertTrue(this.eventFired);
+ }
+
+ /**
+ * test a problem we had where removing a child from a tree would cause
+ * the JTree to call #equals(Object) on each node removed (actually, it was
+ * TreePath, but that was because its own #equals(Object) was called by
+ * JTree); and since we had already removed the last listener from the
+ * aspect adapter, the aspect adapter would say its value was null; this
+ * would cause a NPE until we tweaked TreeModelAdapter to remove its
+ * listeners from a node only *after* the node had been completely
+ * removed from the JTree
+ * @see TreeModelAdapter#removeNode(Object[], int, TreeNodeValueModel)
+ * @see TreeModelAdapter#addNode(Object[], int, TreeNodeValueModel)
+ */
+ public void testLazyInitialization() {
+ TreeModel treeModel = this.buildSpecialTreeModel();
+ JTree jTree = new JTree(treeModel);
+ TestNode rootNode = (TestNode) treeModel.getRoot();
+ TestModel root = rootNode.getTestModel();
+ // this would cause a NPE:
+ root.removeChild(root.childNamed("node 3"));
+ assertEquals(treeModel, jTree.getModel());
+ }
+
+
+ private TreeModel buildSortedTreeModel() {
+ return this.buildTreeModel(this.buildSortedRootNode());
+ }
+
+ private TestNode buildSortedRootNode() {
+ return new SortedTestNode(this.buildRoot());
+ }
+
+ private TreeModel buildUnsortedTreeModel() {
+ return this.buildTreeModel(this.buildUnsortedRootNode());
+ }
+
+ private TestNode buildUnsortedRootNode() {
+ return new UnsortedTestNode(this.buildRoot());
+ }
+
+ private TreeModel buildSpecialTreeModel() {
+ return this.buildTreeModel(this.buildSpecialRootNode());
+ }
+
+ private TestNode buildSpecialRootNode() {
+ return new SpecialTestNode(this.buildRoot());
+ }
+
+ private TestModel buildRoot() {
+ TestModel root = new TestModel("root");
+ /*Node node_0 = */root.addChild("node 0");
+ TestModel node_1 = root.addChild("node 1");
+ TestModel node_1_1 = node_1.addChild("node 1.1");
+ /*Node node_1_1_1 = */node_1_1.addChild("node 1.1.1");
+ TestModel node_2 = root.addChild("node 2");
+ /*Node node_2_0 = */node_2.addChild("node 2.0");
+ /*Node node_2_1 = */node_2.addChild("node 2.1");
+ /*Node node_2_2 = */node_2.addChild("node 2.2");
+ /*Node node_2_3 = */node_2.addChild("node 2.3");
+ /*Node node_2_4 = */node_2.addChild("node 2.4");
+ /*Node node_2_5 = */node_2.addChild("node 2.5");
+ /*Node node_3 = */root.addChild("node 3");
+ /*Node node_4 = */root.addChild("node 4");
+ return root;
+ }
+
+
+ // ********** member classes **********
+
+ /**
+ * This is a typical model class with the typical change notifications
+ * for #name and #children.
+ */
+ public static class TestModel extends AbstractModel {
+
+ // the parent is immutable; the root's parent is null
+ private final TestModel parent;
+
+ // the name is mutable; so I guess it isn't the "primary key" :-)
+ private String name;
+ public static final String NAME_PROPERTY = "name";
+
+ private final Collection<TestModel> children;
+ public static final String CHILDREN_COLLECTION = "children";
+
+
+ public TestModel(String name) { // root ctor
+ this(null, name);
+ }
+ private TestModel(TestModel parent, String name) {
+ super();
+ this.parent = parent;
+ this.name = name;
+ this.children = new HashBag<TestModel>();
+ }
+
+ public TestModel getParent() {
+ return this.parent;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+ public void setName(String name) {
+ Object old = this.name;
+ this.name = name;
+ this.firePropertyChanged(NAME_PROPERTY, old, name);
+ }
+
+ public Iterator<TestModel> children() {
+ return new ReadOnlyIterator<TestModel>(this.children);
+ }
+ public int childrenSize() {
+ return this.children.size();
+ }
+ public TestModel addChild(String childName) {
+ TestModel child = new TestModel(this, childName);
+ this.addItemToCollection(child, this.children, CHILDREN_COLLECTION);
+ return child;
+ }
+ public TestModel[] addChildren(String[] childNames) {
+ TestModel[] newChildren = new TestModel[childNames.length];
+ for (int i = 0; i < childNames.length; i++) {
+ newChildren[i] = new TestModel(this, childNames[i]);
+ }
+ this.addItemsToCollection(newChildren, this.children, CHILDREN_COLLECTION);
+ return newChildren;
+ }
+ public void removeChild(TestModel child) {
+ this.removeItemFromCollection(child, this.children, CHILDREN_COLLECTION);
+ }
+ public void removeChildren(TestModel[] testModels) {
+ this.removeItemsFromCollection(testModels, this.children, CHILDREN_COLLECTION);
+ }
+ public void clearChildren() {
+ this.clearCollection(this.children, CHILDREN_COLLECTION);
+ }
+ public TestModel childNamed(String childName) {
+ for (TestModel child : this.children) {
+ if (child.getName().equals(childName)) {
+ return child;
+ }
+ }
+ throw new RuntimeException("child not found: " + childName);
+ }
+
+ @SuppressWarnings("resource")
+ public String dumpString() {
+ StringWriter sw = new StringWriter();
+ IndentingPrintWriter ipw = new IndentingPrintWriter(sw);
+ this.dumpOn(ipw);
+ return sw.toString();
+ }
+ public void dumpOn(IndentingPrintWriter writer) {
+ writer.println(this);
+ writer.indent();
+ for (TestModel child : this.children) {
+ child.dumpOn(writer);
+ }
+ writer.undent();
+ }
+ @SuppressWarnings("resource")
+ public void dumpOn(OutputStream stream) {
+ IndentingPrintWriter writer = new IndentingPrintWriter(new OutputStreamWriter(stream));
+ this.dumpOn(writer);
+ writer.flush();
+ }
+ public void dump() {
+ this.dumpOn(System.out);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.name);
+ }
+
+ }
+
+
+ /**
+ * This Node wraps a TestModel and converts into something that can
+ * be used by TreeModelAdapter. It converts changes to the TestModel's
+ * name into "state changes" to the Node; and converts the
+ * TestModel's children into a ListValueModel of Nodes whose order is
+ * determined by subclass implementations.
+ */
+ public static abstract class TestNode extends AbstractTreeNodeValueModel<Object> implements Displayable, Comparable<TestNode> {
+ /** the model object wrapped by this node */
+ private final TestModel testModel;
+ /** this node's parent node; null for the root node */
+ private final TestNode parent;
+ /** this node's child nodes */
+ private final ListValueModel<TreeNodeValueModel<Object>> childrenModel;
+ /** a listener that notifies us when the model object's "internal state" changes */
+ private final PropertyChangeListener testModelListener;
+
+
+ // ********** constructors/initialization **********
+
+ /**
+ * root node constructor
+ */
+ public TestNode(TestModel testModel) {
+ this(null, testModel);
+ }
+
+ /**
+ * branch or leaf node constructor
+ */
+ public TestNode(TestNode parent, TestModel testModel) {
+ super();
+ this.parent = parent;
+ this.testModel = testModel;
+ this.childrenModel = this.buildChildrenModel(testModel);
+ this.testModelListener = this.buildTestModelListener();
+ }
+
+ private PropertyChangeListener buildTestModelListener() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ TestNode.this.testModelChanged(e);
+ }
+ };
+ }
+
+ /**
+ * subclasses decide the order of the child nodes
+ */
+ protected abstract ListValueModel<TreeNodeValueModel<Object>> buildChildrenModel(TestModel model);
+
+ /**
+ * used by subclasses;
+ * transform the test model children into nodes
+ */
+ protected ListValueModel<TreeNodeValueModel<Object>> buildNodeAdapter(TestModel model) {
+ return new TransformationListValueModel<TestModel, TreeNodeValueModel<Object>>(this.buildChildrenAdapter(model)) {
+ @Override
+ protected TestNode transformItem(TestModel item) {
+ return TestNode.this.buildChildNode(item);
+ }
+ };
+ }
+
+ /**
+ * subclasses must build a concrete node for the specified test model
+ */
+ protected abstract TestNode buildChildNode(TestModel childTestModel);
+
+ /**
+ * return a collection value model on the specified model's children
+ */
+ protected CollectionValueModel<TestModel> buildChildrenAdapter(TestModel model) {
+ return new CollectionAspectAdapter<TestModel, TestModel>(TestModel.CHILDREN_COLLECTION, model) {
+ @Override
+ protected Iterator<TestModel> iterator_() {
+ return this.subject.children();
+ }
+ @Override
+ protected int size_() {
+ return this.subject.childrenSize();
+ }
+ };
+ }
+
+
+ // ********** TreeNodeValueModel implementation **********
+
+ @Override
+ public TestModel getValue() {
+ return this.testModel;
+ }
+
+ @Override
+ public TreeNodeValueModel<Object> parent() {
+ return this.parent;
+ }
+
+ @Override
+ public ListValueModel<TreeNodeValueModel<Object>> childrenModel() {
+ return this.childrenModel;
+ }
+
+
+ // ********** AbstractTreeNodeValueModel implementation **********
+
+ @Override
+ protected void engageValue() {
+ this.testModel.addPropertyChangeListener(TestModel.NAME_PROPERTY, this.testModelListener);
+ }
+
+ @Override
+ protected void disengageValue() {
+ this.testModel.removePropertyChangeListener(TestModel.NAME_PROPERTY, this.testModelListener);
+ }
+
+
+ // ********** Displayable implementation **********
+
+ @Override
+ public String displayString() {
+ return this.testModel.getName();
+ }
+
+ @Override
+ public Icon icon() {
+ return null;
+ }
+
+
+ // ********** debugging support **********
+
+ @SuppressWarnings("resource")
+ public String dumpString() {
+ StringWriter sw = new StringWriter();
+ IndentingPrintWriter ipw = new IndentingPrintWriter(sw);
+ this.dumpOn(ipw);
+ return sw.toString();
+ }
+
+ public void dumpOn(IndentingPrintWriter writer) {
+ writer.println(this);
+ writer.indent();
+ for (Iterator<TreeNodeValueModel<Object>> stream = this.childrenModel.iterator(); stream.hasNext(); ) {
+ // cast to a TestNode (i.e. this won't work with a NameTestNode in the tree)
+ ((TestNode) stream.next()).dumpOn(writer);
+ }
+ writer.undent();
+ }
+
+ @SuppressWarnings("resource")
+ public void dumpOn(OutputStream stream) {
+ IndentingPrintWriter writer = new IndentingPrintWriter(new OutputStreamWriter(stream));
+ this.dumpOn(writer);
+ writer.flush();
+ }
+
+ public void dump() {
+ this.dumpOn(System.out);
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * the model's name has changed, forward the event to our listeners
+ */
+ protected void testModelChanged(PropertyChangeEvent e) {
+ // we need to notify listeners that our "internal state" has changed
+ this.fireStateChanged();
+ // our display string stays in synch with the model's name
+ this.firePropertyChanged(DISPLAY_STRING_PROPERTY, e.getOldValue(), e.getNewValue());
+ }
+
+
+ // ********** queries **********
+
+ public TestModel getTestModel() {
+ return this.testModel;
+ }
+
+ /**
+ * testing convenience method
+ */
+ public TestNode childNamed(String name) {
+ for (Iterator<TreeNodeValueModel<Object>> stream = this.childrenModel.iterator(); stream.hasNext(); ) {
+ TreeNodeValueModel<Object> childNode = stream.next();
+ if (childNode instanceof TestNode) {
+ if (((TestNode) childNode).getTestModel().getName().equals(name)) {
+ return (TestNode) childNode;
+ }
+ }
+ }
+ throw new IllegalArgumentException("child not found: " + name);
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public int compareTo(TestNode o) {
+ return this.displayString().compareTo(o.displayString());
+ }
+
+ @Override
+ public String toString() {
+ return "Node(" + this.testModel + ")";
+ }
+
+ }
+
+ /**
+ * concrete implementation that keeps its children sorted
+ */
+ public static class SortedTestNode extends TestNode {
+
+ // ********** constructors **********
+ public SortedTestNode(TestModel testModel) {
+ super(testModel);
+ }
+ public SortedTestNode(TestNode parent, TestModel testModel) {
+ super(parent, testModel);
+ }
+
+ // ********** initialization **********
+ /** the list should be sorted */
+ @Override
+ protected ListValueModel<TreeNodeValueModel<Object>> buildChildrenModel(TestModel testModel) {
+ return new SortedListValueModelWrapper<TreeNodeValueModel<Object>>(this.buildDisplayStringAdapter(testModel));
+ }
+ /** the display string (name) of each node can change */
+ protected ListValueModel<TreeNodeValueModel<Object>> buildDisplayStringAdapter(TestModel testModel) {
+ return new ItemPropertyListValueModelAdapter<TreeNodeValueModel<Object>>(this.buildNodeAdapter(testModel), DISPLAY_STRING_PROPERTY);
+ }
+ /** children are also sorted nodes */
+ @Override
+ protected TestNode buildChildNode(TestModel childNode) {
+ return new SortedTestNode(this, childNode);
+ }
+
+ }
+
+
+ /**
+ * concrete implementation that leaves its children unsorted
+ */
+ public static class UnsortedTestNode extends TestNode {
+
+ // ********** constructors **********
+ public UnsortedTestNode(TestModel testModel) {
+ super(testModel);
+ }
+ public UnsortedTestNode(TestNode parent, TestModel testModel) {
+ super(parent, testModel);
+ }
+
+ // ********** initialization **********
+ /** the list should NOT be sorted */
+ @Override
+ protected ListValueModel<TreeNodeValueModel<Object>> buildChildrenModel(TestModel testModel) {
+ return this.buildNodeAdapter(testModel);
+ }
+ /** children are also unsorted nodes */
+ @Override
+ protected TestNode buildChildNode(TestModel childNode) {
+ return new UnsortedTestNode(this, childNode);
+ }
+
+ }
+
+
+ /**
+ * concrete implementation that leaves its children unsorted
+ * and has a special set of children for "node 3"
+ */
+ public static class SpecialTestNode extends UnsortedTestNode {
+
+ // ********** constructors **********
+ public SpecialTestNode(TestModel testModel) {
+ super(testModel);
+ }
+ public SpecialTestNode(TestNode parent, TestModel testModel) {
+ super(parent, testModel);
+ }
+
+ // ********** initialization **********
+ /** return a different list of children for "node 3" */
+ @Override
+ protected ListValueModel<TreeNodeValueModel<Object>> buildChildrenModel(TestModel testModel) {
+ if (testModel.getName().equals("node 3")) {
+ return this.buildSpecialChildrenModel();
+ }
+ return super.buildChildrenModel(testModel);
+ }
+ protected ListValueModel<TreeNodeValueModel<Object>> buildSpecialChildrenModel() {
+ TreeNodeValueModel<Object>[] children = new NameTestNode[1];
+ children[0] = new NameTestNode(this);
+ return new SimpleListValueModel<TreeNodeValueModel<Object>>(Arrays.asList(children));
+ }
+ /** children are also special nodes */
+ @Override
+ protected TestNode buildChildNode(TestModel childNode) {
+ return new SpecialTestNode(this, childNode);
+ }
+
+ }
+
+
+ public static class NameTestNode extends AbstractTreeNodeValueModel<Object> {
+ private final ModifiablePropertyValueModel<String> nameAdapter;
+ private final SpecialTestNode specialNode; // parent node
+ private final PropertyChangeListener nameListener;
+ private final ListValueModel<TreeNodeValueModel<Object>> childrenModel;
+
+ // ********** construction/initialization **********
+
+ public NameTestNode(SpecialTestNode specialNode) {
+ super();
+ this.nameListener = this.buildNameListener();
+ this.specialNode = specialNode;
+ this.nameAdapter = this.buildNameAdapter();
+ this.childrenModel = new NullListValueModel<TreeNodeValueModel<Object>>();
+ }
+ protected PropertyChangeListener buildNameListener() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ NameTestNode.this.nameChanged(e);
+ }
+ };
+ }
+ protected ModifiablePropertyValueModel<String> buildNameAdapter() {
+ return new PropertyAspectAdapter<TestModel, String>(TestModel.NAME_PROPERTY, this.getTestModel()) {
+ @Override
+ protected String buildValue_() {
+ return this.subject.getName();
+ }
+ @Override
+ protected void setValue_(String value) {
+ this.subject.setName(value);
+ }
+ };
+ }
+
+ public TestModel getTestModel() {
+ return this.specialNode.getTestModel();
+ }
+
+ // ********** TreeNodeValueModel implementation **********
+
+ @Override
+ public String getValue() {
+ return this.nameAdapter.getValue();
+ }
+ @Override
+ public void setValue(Object value) {
+ this.nameAdapter.setValue((String) value);
+ }
+ @Override
+ public TreeNodeValueModel<Object> parent() {
+ return this.specialNode;
+ }
+ @Override
+ public ListValueModel<TreeNodeValueModel<Object>> childrenModel() {
+ return this.childrenModel;
+ }
+
+ // ********** AbstractTreeNodeValueModel implementation **********
+
+ @Override
+ protected void engageValue() {
+ this.nameAdapter.addPropertyChangeListener(PropertyValueModel.VALUE, this.nameListener);
+ }
+ @Override
+ protected void disengageValue() {
+ this.nameAdapter.removePropertyChangeListener(PropertyValueModel.VALUE, this.nameListener);
+ }
+
+ // ********** behavior **********
+
+ protected void nameChanged(PropertyChangeEvent e) {
+ // we need to notify listeners that our "value" has changed
+ this.firePropertyChanged(VALUE, e.getOldValue(), e.getNewValue());
+ }
+ }
+
+ private TreeModel buildTreeModel(TestNode root) {
+ return this.buildTreeModel(new StaticPropertyValueModel<TreeNodeValueModel<Object>>(root));
+ }
+
+ private TreeModel buildTreeModel(PropertyValueModel<TreeNodeValueModel<Object>> rootHolder) {
+ return new TreeModelAdapter<Object>(rootHolder) {
+ @Override
+ protected ListChangeListener buildChildrenListener() {
+ return this.buildChildrenListener_();
+ }
+ @Override
+ protected StateChangeListener buildNodeStateListener() {
+ return this.buildNodeStateListener_();
+ }
+ @Override
+ protected PropertyChangeListener buildNodeValueListener() {
+ return this.buildNodeValueListener_();
+ }
+ @Override
+ protected PropertyChangeListener buildRootListener() {
+ return this.buildRootListener_();
+ }
+ };
+ }
+
+
+
+ /**
+ * listener that will blow up with any event;
+ * override and implement expected event methods
+ */
+ public class TestTreeModelListener implements TreeModelListener {
+ @Override
+ public void treeNodesChanged(TreeModelEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void treeNodesInserted(TreeModelEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void treeNodesRemoved(TreeModelEvent e) {
+ fail("unexpected event");
+ }
+ @Override
+ public void treeStructureChanged(TreeModelEvent e) {
+ fail("unexpected event");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterUITest.java
new file mode 100644
index 0000000..b30cca8
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterUITest.java
@@ -0,0 +1,434 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.WindowConstants;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.iterator.EnumerationIterator;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TreeNodeValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.TreeModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TreeModelAdapterTests.SortedTestNode;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TreeModelAdapterTests.TestModel;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TreeModelAdapterTests.TestNode;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TreeModelAdapterTests.UnsortedTestNode;
+
+/**
+ * an example UI for testing the TreeModelAdapter
+ */
+@SuppressWarnings("nls")
+public class TreeModelAdapterUITest {
+
+ // hold the tree so we can restore its expansion state
+ private JTree tree;
+ private ModifiablePropertyValueModel<TreeNodeValueModel<Object>> rootNodeHolder;
+ private boolean sorted;
+ private TreeModel treeModel;
+ private TreeSelectionModel treeSelectionModel;
+ private TextField nameTextField;
+
+ public static void main(String[] args) throws Exception {
+ new TreeModelAdapterUITest().exec();
+ }
+
+ private TreeModelAdapterUITest() {
+ super();
+ }
+
+ private void exec() throws Exception {
+ this.rootNodeHolder = this.buildRootNodeHolder();
+ this.sorted = this.rootNodeHolder.getValue() instanceof SortedTestNode;
+ this.treeModel = this.buildTreeModel();
+ this.treeSelectionModel = this.buildTreeSelectionModel();
+ this.nameTextField = new TextField();
+ this.openWindow();
+ }
+
+ private ModifiablePropertyValueModel<TreeNodeValueModel<Object>> buildRootNodeHolder() {
+ return new SimplePropertyValueModel<TreeNodeValueModel<Object>>(this.buildSortedRootNode());
+ }
+
+ private TestNode buildSortedRootNode() {
+ return new SortedTestNode(this.buildRoot());
+ }
+
+ private TestNode buildUnsortedRootNode() {
+ return new UnsortedTestNode(this.buildRoot());
+ }
+
+ private TestModel buildRoot() {
+ TestModel root = new TestModel("root");
+
+ TestModel node_1 = root.addChild("node 1");
+ /*Node node_1_1 = */node_1.addChild("node 1.1");
+
+ TestModel node_2 = root.addChild("node 2");
+ /*Node node_2_1 = */node_2.addChild("node 2.1");
+ TestModel node_2_2 = node_2.addChild("node 2.2");
+ /*Node node_2_2_1 = */node_2_2.addChild("node 2.2.1");
+ /*Node node_2_2_2 = */node_2_2.addChild("node 2.2.2");
+ /*Node node_2_3 = */node_2.addChild("node 2.3");
+ /*Node node_2_4 = */node_2.addChild("node 2.4");
+ /*Node node_2_5 = */node_2.addChild("node 2.5");
+
+ TestModel node_3 = root.addChild("node 3");
+ TestModel node_3_1 = node_3.addChild("node 3.1");
+ TestModel node_3_1_1 = node_3_1.addChild("node 3.1.1");
+ /*Node node_3_1_1_1 = */node_3_1_1.addChild("node 3.1.1.1");
+
+ /*Node node_4 = */root.addChild("node 4");
+
+ return root;
+ }
+
+ private TreeModel buildTreeModel() {
+ return new TreeModelAdapter<Object>(this.rootNodeHolder);
+ }
+
+ private TreeSelectionModel buildTreeSelectionModel() {
+ TreeSelectionModel tsm = new DefaultTreeSelectionModel();
+ tsm.addTreeSelectionListener(this.buildTreeSelectionListener());
+ tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+ return tsm;
+ }
+
+ private TreeSelectionListener buildTreeSelectionListener() {
+ return new TreeSelectionListener() {
+ @Override
+ public void valueChanged(TreeSelectionEvent e) {
+ TreeModelAdapterUITest.this.treeSelectionChanged(e);
+ }
+ };
+ }
+
+ void treeSelectionChanged(@SuppressWarnings("unused") TreeSelectionEvent e) {
+ TestModel selectedTestModel = this.selectedTestModel();
+ if (selectedTestModel != null) {
+ this.nameTextField.setText(selectedTestModel.getName());
+ }
+ }
+
+ private void openWindow() {
+ JFrame window = new JFrame(this.getClass().getName());
+ window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ window.addWindowListener(this.buildWindowListener());
+ window.getContentPane().add(this.buildMainPanel(), "Center");
+ window.setLocation(300, 300);
+ window.setSize(400, 400);
+ window.setVisible(true);
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private Component buildMainPanel() {
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(this.buildTreePane(), BorderLayout.CENTER);
+ mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ private Component buildTreePane() {
+ return new JScrollPane(this.buildTree());
+ }
+
+ private JTree buildTree() {
+ this.tree = new JTree(this.treeModel) {
+ @Override
+ public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+ return ((Displayable) value).displayString();
+ }
+ };
+ this.tree.setSelectionModel(this.treeSelectionModel);
+ this.tree.setRootVisible(true);
+ this.tree.setShowsRootHandles(true);
+ this.tree.setRowHeight(20);
+ this.tree.setDoubleBuffered(true);
+ return this.tree;
+ }
+
+ private Component buildControlPanel() {
+ JPanel controlPanel = new JPanel(new GridLayout(0, 1));
+ controlPanel.add(this.buildAddRenameNodePanel());
+ controlPanel.add(this.buildMiscPanel());
+ return controlPanel;
+ }
+
+ private Component buildAddRenameNodePanel() {
+ JPanel addRenameNodePanel = new JPanel(new BorderLayout());
+ addRenameNodePanel.add(this.buildAddButton(), BorderLayout.WEST);
+ addRenameNodePanel.add(this.nameTextField, BorderLayout.CENTER);
+ addRenameNodePanel.add(this.buildRenameButton(), BorderLayout.EAST);
+ return addRenameNodePanel;
+ }
+
+ private Component buildMiscPanel() {
+ JPanel miscPanel = new JPanel(new GridLayout(1, 0));
+ miscPanel.add(this.buildClearChildrenButton());
+ miscPanel.add(this.buildRemoveButton());
+ miscPanel.add(this.buildResetButton());
+ return miscPanel;
+ }
+
+ private String getName() {
+ return this.nameTextField.getText();
+ }
+
+ // ********** queries **********
+ private TestNode selectedNode() {
+ if (this.treeSelectionModel.isSelectionEmpty()) {
+ return null;
+ }
+ return (TestNode) this.treeSelectionModel.getSelectionPath().getLastPathComponent();
+ }
+
+ private TestModel selectedTestModel() {
+ if (this.treeSelectionModel.isSelectionEmpty()) {
+ return null;
+ }
+ return this.selectedNode().getValue();
+ }
+
+ private TestNode rootNode() {
+ return (TestNode) this.treeModel.getRoot();
+ }
+
+ private TestModel root() {
+ return this.rootNode().getValue();
+ }
+
+ private Collection<TreePath> expandedPaths() {
+ Enumeration<TreePath> stream = this.tree.getExpandedDescendants(new TreePath(this.rootNode()));
+ if (stream == null) {
+ return Collections.emptyList();
+ }
+ return ListTools.list(new EnumerationIterator<TreePath>(stream));
+ }
+
+ // ********** behavior **********
+ private void setSelectedNode(TestNode selectedNode) {
+ this.treeSelectionModel.setSelectionPath(new TreePath(selectedNode.path()));
+ }
+
+ private void expandPaths(Collection<TreePath> paths) {
+ for (TreePath path : paths) {
+ this.tree.expandPath(path);
+ }
+ }
+
+ // ********** add **********
+ private JButton buildAddButton() {
+ return new JButton(this.buildAddAction());
+ }
+
+ private Action buildAddAction() {
+ Action action = new AbstractAction("add") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TreeModelAdapterUITest.this.addNode();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ /**
+ * adding causes the tree to be sorted and nodes to be
+ * removed and re-added; so we have to fiddle with the expansion state
+ */
+ void addNode() {
+ TestModel selectedTestModel = this.selectedTestModel();
+ if (selectedTestModel != null) {
+ String name = this.getName();
+ // save the expansion state and restore it after the add
+ Collection<TreePath> paths = this.expandedPaths();
+
+ selectedTestModel.addChild(name);
+
+ this.expandPaths(paths);
+ this.setSelectedNode(this.selectedNode().childNamed(name));
+ }
+ }
+
+ // ********** remove **********
+ private JButton buildRemoveButton() {
+ return new JButton(this.buildRemoveAction());
+ }
+
+ private Action buildRemoveAction() {
+ Action action = new AbstractAction("remove") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TreeModelAdapterUITest.this.removeNode();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ /**
+ * we need to figure out which node to select after
+ * the selected node is deleted
+ */
+ void removeNode() {
+ TestModel selectedTestModel = this.selectedTestModel();
+ // do not allow the root to be removed
+ if ((selectedTestModel != null) && (selectedTestModel != this.root())) {
+ // save the parent and index, so we can select another, nearby, node
+ // once the selected node is removed
+ TestNode parentNode = (TestNode) this.selectedNode().parent();
+ int childIndex = parentNode.indexOfChild(this.selectedNode());
+
+ selectedTestModel.getParent().removeChild(selectedTestModel);
+
+ int childrenSize = parentNode.childrenSize();
+ if (childIndex < childrenSize) {
+ // select the child that moved up and replaced the just-deleted child
+ this.setSelectedNode((TestNode) parentNode.child(childIndex));
+ } else {
+ if (childrenSize == 0) {
+ // if there are no more children, select the parent
+ this.setSelectedNode(parentNode);
+ } else {
+ // if the child at the bottom of the list was deleted, select the next child up
+ this.setSelectedNode((TestNode) parentNode.child(childIndex - 1));
+ }
+ }
+ }
+ }
+
+ // ********** rename **********
+ private JButton buildRenameButton() {
+ return new JButton(this.buildRenameAction());
+ }
+
+ private Action buildRenameAction() {
+ Action action = new AbstractAction("rename") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TreeModelAdapterUITest.this.renameNode();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ /**
+ * renaming causes the tree to be sorted and nodes to be
+ * removed and re-added; so we have to fiddle with the expansion state
+ */
+ void renameNode() {
+ TestModel selectedTestModel = this.selectedTestModel();
+ if (selectedTestModel != null) {
+ // save the node and re-select it after the rename
+ TestNode selectedNode = this.selectedNode();
+ // save the expansion state and restore it after the rename
+ Collection<TreePath> paths = this.expandedPaths();
+
+ selectedTestModel.setName(this.getName());
+
+ this.expandPaths(paths);
+ this.setSelectedNode(selectedNode);
+ }
+ }
+
+ // ********** clear children **********
+ private JButton buildClearChildrenButton() {
+ return new JButton(this.buildClearChildrenAction());
+ }
+
+ private Action buildClearChildrenAction() {
+ Action action = new AbstractAction("clear children") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TreeModelAdapterUITest.this.clearChildren();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ /**
+ * nothing special, we just want to test #fireCollectionChanged(String)
+ */
+ void clearChildren() {
+ TestModel selectedTestModel = this.selectedTestModel();
+ if (selectedTestModel != null) {
+ selectedTestModel.clearChildren();
+ }
+ }
+
+ // ********** reset **********
+ private JButton buildResetButton() {
+ return new JButton(this.buildResetAction());
+ }
+
+ private Action buildResetAction() {
+ Action action = new AbstractAction("reset") {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ TreeModelAdapterUITest.this.reset();
+ }
+ };
+ action.setEnabled(true);
+ return action;
+ }
+
+ /**
+ * test the adapter's root node holder;
+ * toggle between sorted and unsorted lists
+ */
+ void reset() {
+ this.sorted = ! this.sorted;
+ if (this.sorted) {
+ this.rootNodeHolder.setValue(this.buildSortedRootNode());
+ } else {
+ this.rootNodeHolder.setValue(this.buildUnsortedRootNode());
+ }
+ this.tree.expandPath(new TreePath(this.rootNode()));
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/UtilityModelValueSwingTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/UtilityModelValueSwingTests.java
new file mode 100644
index 0000000..e8b623d
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/UtilityModelValueSwingTests.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class UtilityModelValueSwingTests {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(UtilityModelValueSwingTests.class.getPackage().getName());
+
+ suite.addTestSuite(CheckBoxModelAdapterTests.class);
+ suite.addTestSuite(ComboBoxModelAdapterTests.class);
+ suite.addTestSuite(DateSpinnerModelAdapterTests.class);
+ suite.addTestSuite(DocumentAdapterTests.class);
+ suite.addTestSuite(ListModelAdapterTests.class);
+ suite.addTestSuite(ListSpinnerModelAdapterTests.class);
+ suite.addTestSuite(NumberSpinnerModelAdapterTests.class);
+ suite.addTestSuite(ObjectListSelectionModelTests.class);
+ suite.addTestSuite(PrimitiveListTreeModelTests.class);
+ suite.addTestSuite(RadioButtonModelAdapterTests.class);
+ suite.addTestSuite(SpinnerModelAdapterTests.class);
+ suite.addTestSuite(TableModelAdapterTests.class);
+ suite.addTestSuite(TreeModelAdapterTests.class);
+
+ return suite;
+ }
+
+ private UtilityModelValueSwingTests() {
+ super();
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/swing/FilteringListPanelUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/swing/FilteringListPanelUITest.java
new file mode 100644
index 0000000..7c4ac59
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/swing/FilteringListPanelUITest.java
@@ -0,0 +1,351 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.UIManager;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.ArrayTools;
+import org.eclipse.persistence.tools.utility.ClassNameTools;
+import org.eclipse.persistence.tools.utility.Classpath;
+import org.eclipse.persistence.tools.utility.StringTools;
+import org.eclipse.persistence.tools.utility.iterable.TransformationIterable;
+import org.eclipse.persistence.tools.utility.swing.FilteringListPanel;
+import org.eclipse.persistence.tools.utility.swing.SimpleListCellRenderer;
+import org.eclipse.persistence.tools.utility.transformer.Transformer;
+import org.eclipse.persistence.tools.utility.transformer.TransformerAdapter;
+
+/**
+ * Simple test class for playing around with {@link FilteringListPanel}.
+ * <p>
+ * Optional command line parm:<ul>
+ * <li>the name of a jar (or class folder) to use to populate the list box
+ * </ul>
+ */
+@SuppressWarnings("nls")
+public class FilteringListPanelUITest {
+ private Type[] completeList1;
+ private Type[] completeList2;
+ private FilteringListPanel<Type> filteringListPanel;
+ private Font font;
+
+
+ public static void main(String[] args) {
+ new FilteringListPanelUITest().exec(args);
+ }
+
+ private FilteringListPanelUITest() {
+ super();
+ this.initialize();
+ }
+
+ private void initialize() {
+ this.font = this.buildFont();
+ }
+
+ private Font buildFont() {
+ return new Font("Dialog", Font.PLAIN, 12);
+ }
+
+ private void exec(String[] args) {
+ this.completeList1 = this.buildTypeList(args);
+ this.completeList2 = this.buildCompleteList2();
+ JFrame frame = new JFrame(this.getClass().getSimpleName());
+ frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ frame.addWindowListener(this.buildWindowListener());
+ frame.getContentPane().add(this.buildMainPanel(), "Center");
+ frame.setLocation(300, 300);
+ frame.setSize(400, 400);
+ frame.setVisible(true);
+ }
+
+ private Type[] buildTypeList(String[] args) {
+ return ArrayTools.sort(ArrayTools.array(this.buildTypes(args), Type.class));
+ }
+
+ private Type[] buildCompleteList2() {
+ String classpathEntry = Classpath.locationFor(this.getClass());
+ return ArrayTools.sort(ArrayTools.array(this.buildTypes(new String[] {classpathEntry}), Type.class));
+ }
+
+ private Iterable<Type> buildTypes(String[] args) {
+ return new TransformationIterable<String, Type>(this.buildClassNames(args), TYPE_STRING_TRANSFORMER);
+ }
+
+ private static final Transformer<String, Type> TYPE_STRING_TRANSFORMER = new TypeStringTransformer();
+ /* CU private */ static class TypeStringTransformer
+ extends TransformerAdapter<String, Type>
+ {
+ @Override
+ public Type transform(String string) {
+ return new Type(string);
+ }
+ }
+
+ private Iterable<String> buildClassNames(String[] args) {
+ return ((args == null) || (args.length == 0)) ?
+ Classpath.bootClasspath().getClassNames() :
+ new Classpath(new String[] { args[0] }).getClassNames();
+ }
+
+ private WindowListener buildWindowListener() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ e.getWindow().setVisible(false);
+ System.exit(0);
+ }
+ };
+ }
+
+ private JPanel buildMainPanel() {
+ JPanel panel = new JPanel(new BorderLayout());
+ this.filteringListPanel = this.buildFilteringListPanel();
+ panel.add(this.filteringListPanel, BorderLayout.CENTER);
+ panel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+ return panel;
+ }
+
+ private FilteringListPanel<Type> buildFilteringListPanel() {
+ Type initialSelection = this.getTypeNamed(this.completeList1, "java.lang.Object");
+ FilteringListPanel<Type> panel = new FilteringListPanel<Type>(this.completeList1, initialSelection, TYPE_NAME_TRANSFORMER);
+ panel.setTextFieldLabelText("Choose a Type (? = any char, * = any string):");
+ panel.setListBoxLabelText("Matching Types:");
+ panel.setComponentsFont(this.font);
+ panel.setListBoxCellRenderer(new TypeCellRenderer());
+ return panel;
+ }
+
+ private static final Transformer<Type, String> TYPE_NAME_TRANSFORMER = new TypeNameTransformer();
+ /* CU private */ static class TypeNameTransformer
+ extends TransformerAdapter<Type, String>
+ {
+ @Override
+ public String transform(Type type) {
+ return (type == null) ? StringTools.EMPTY_STRING : type.getName();
+ }
+ }
+
+ /* CU private */ class TypeCellRenderer
+ extends SimpleListCellRenderer
+ {
+ private static final long serialVersionUID = 1L;
+ @Override
+ protected Icon buildIcon(Object value) {
+ return UIManager.getIcon("Tree.leafIcon");
+ }
+ @Override
+ protected String buildText(Object value) {
+ return ((Type) value).getName();
+ }
+ }
+
+ private JPanel buildControlPanel() {
+ JPanel panel = new JPanel(new GridLayout(1, 0));
+ panel.add(this.buildSwapButton());
+ panel.add(this.buildStringButton());
+ panel.add(this.buildNullButton());
+ panel.add(this.buildMax10Button());
+ panel.add(this.buildPrintButton());
+ return panel;
+ }
+
+ // ********** swap button **********
+
+ private JButton buildSwapButton() {
+ JButton button = new JButton(this.buildSwapAction());
+ button.setFont(this.font);
+ return button;
+ }
+
+ private Action buildSwapAction() {
+ return new AbstractAction("swap") {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ FilteringListPanelUITest.this.swap();
+ }
+ };
+ }
+
+ /**
+ * swap in a new list
+ */
+ void swap() {
+ if (this.filteringListPanel.getCompleteList() == this.completeList1) {
+ this.filteringListPanel.setCompleteList(this.completeList2);
+ } else {
+ this.filteringListPanel.setCompleteList(this.completeList1);
+ }
+ }
+
+ // ********** string button **********
+
+ private JButton buildStringButton() {
+ JButton button = new JButton(this.buildStringAction());
+ button.setFont(this.font);
+ return button;
+ }
+
+ private Action buildStringAction() {
+ return new AbstractAction("String") {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ FilteringListPanelUITest.this.selectStringType();
+ }
+ };
+ }
+
+ /**
+ * force a selection from "outside" the filtering list panel
+ */
+ void selectStringType() {
+ this.filteringListPanel.setSelection(this.typeNamed("java.lang.String"));
+ }
+
+ private Type typeNamed(String name) {
+ return this.getTypeNamed(this.filteringListPanel.getCompleteList(), name);
+ }
+
+ private Type getTypeNamed(Type[] types, String name) {
+ for (int i = types.length; i-- > 0; ) {
+ Type type = types[i];
+ if (type.getName().equals(name)) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ // ********** null button **********
+
+ private JButton buildNullButton() {
+ JButton button = new JButton(this.buildNullAction());
+ button.setFont(this.font);
+ return button;
+ }
+
+ private Action buildNullAction() {
+ return new AbstractAction("null") {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ FilteringListPanelUITest.this.selectNull();
+ }
+ };
+ }
+
+ /**
+ * set the current selection to null
+ */
+ void selectNull() {
+ this.filteringListPanel.setSelection(null);
+ }
+
+ // ********** null button **********
+
+ private JButton buildMax10Button() {
+ JButton button = new JButton(this.buildMax10Action());
+ button.setFont(this.font);
+ return button;
+ }
+
+ private Action buildMax10Action() {
+ return new AbstractAction("max = 10") {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ FilteringListPanelUITest.this.setMax10();
+ }
+ };
+ }
+
+ /**
+ * toggle between allowing only 10 entries in the list box
+ * and no limit
+ */
+ void setMax10() {
+ if (this.filteringListPanel.getMaxListSize() == 10) {
+ this.filteringListPanel.setMaxListSize(-1);
+ } else {
+ this.filteringListPanel.setMaxListSize(10);
+ }
+ }
+
+ // ********** print button **********
+
+ private JButton buildPrintButton() {
+ JButton button = new JButton(this.buildPrintAction());
+ button.setFont(this.font);
+ return button;
+ }
+
+ private Action buildPrintAction() {
+ return new AbstractAction("print") {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ FilteringListPanelUITest.this.printType();
+ }
+ };
+ }
+
+ /**
+ * print the currently selected type to the console
+ */
+ void printType() {
+ System.out.println("selected item: " + this.filteringListPanel.getSelection());
+ }
+
+
+ // ********** type **********
+
+ /* CU private */ static class Type
+ implements Comparable<Type>
+ {
+ private String name;
+
+ Type(String name) {
+ super();
+ this.name = name;
+ }
+ public String shortName() {
+ return ClassNameTools.simpleName(this.name);
+ }
+ public String getName() {
+ return this.name;
+ }
+ @Override
+ public String toString() {
+ return "Type: " + this.name ;
+ }
+ @Override
+ public int compareTo(Type type) {
+ return this.name.compareTo(type.name);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/META-INF/MANIFEST.MF b/tools/org.eclipse.persistence.tools.utility/META-INF/MANIFEST.MF
index 85b1973..982ee8a 100644
--- a/tools/org.eclipse.persistence.tools.utility/META-INF/MANIFEST.MF
+++ b/tools/org.eclipse.persistence.tools.utility/META-INF/MANIFEST.MF
@@ -12,12 +12,15 @@
org.eclipse.persistence.tools.utility.model;version="2.5.0",
org.eclipse.persistence.tools.utility.model.event;version="2.5.0",
org.eclipse.persistence.tools.utility.model.listener;version="2.5.0",
+ org.eclipse.persistence.tools.utility.model.listener.awt;version="2.5.0",
org.eclipse.persistence.tools.utility.model.value;version="2.5.0",
org.eclipse.persistence.tools.utility.model.value.prefs;version="2.5.0",
+ org.eclipse.persistence.tools.utility.model.value.swing;version="2.5.0",
org.eclipse.persistence.tools.utility.node;version="2.5.0",
org.eclipse.persistence.tools.utility.prefs;version="2.5.0",
org.eclipse.persistence.tools.utility.reference;version="2.5.0",
org.eclipse.persistence.tools.utility.status;version="2.5.0",
+ org.eclipse.persistence.tools.utility.swing;version="2.5.0",
org.eclipse.persistence.tools.utility.transformer;version="2.5.0"
Bundle-ClassPath: .
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
diff --git a/tools/org.eclipse.persistence.tools.utility/pom.xml b/tools/org.eclipse.persistence.tools.utility/pom.xml
index a63a20a..55c43f1 100644
--- a/tools/org.eclipse.persistence.tools.utility/pom.xml
+++ b/tools/org.eclipse.persistence.tools.utility/pom.xml
@@ -16,4 +16,18 @@
<relativePath>../org.eclipse.persistence.tools.parent/pom.xml</relativePath>
</parent>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>tycho-compiler-plugin</artifactId>
+ <version>${tycho.version}</version>
+ <configuration>
+ <!-- Remove the restriction to access restricted classes, such as Swing classes. -->
+ <compilerArgument>-err:-forbidden</compilerArgument>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
</project>
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTChangeListenerWrapper.java
new file mode 100644
index 0000000..8985bfb
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTChangeListenerWrapper.java
@@ -0,0 +1,381 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.model.event.CollectionAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.StateChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+
+/**
+ * Wrap another change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited.
+ */
+@SuppressWarnings("nls")
+public final class AWTChangeListenerWrapper
+ implements ChangeListener
+{
+ private final ChangeListener listener;
+
+
+ public AWTChangeListenerWrapper(ChangeListener listener) {
+ super();
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ }
+
+ @Override
+ public void stateChanged(StateChangeEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.stateChanged_(event);
+ } else {
+ this.executeOnEventQueue(this.buildStateChangedRunnable(event));
+ }
+ }
+
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.propertyChanged_(event);
+ } else {
+ this.executeOnEventQueue(this.buildPropertyChangedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsAdded(CollectionAddEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsAdded_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsRemoved(CollectionRemoveEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsRemoved_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
+ }
+ }
+
+ @Override
+ public void collectionCleared(CollectionClearEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.collectionCleared_(event);
+ } else {
+ this.executeOnEventQueue(this.buildCollectionClearedRunnable(event));
+ }
+ }
+
+ @Override
+ public void collectionChanged(CollectionChangeEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.collectionChanged_(event);
+ } else {
+ this.executeOnEventQueue(this.buildCollectionChangedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsAdded(ListAddEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsAdded_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsRemoved_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsMoved(ListMoveEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsMoved_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsMovedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsReplaced_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsReplacedRunnable(event));
+ }
+ }
+
+ @Override
+ public void listCleared(ListClearEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.listCleared_(event);
+ } else {
+ this.executeOnEventQueue(this.buildListClearedRunnable(event));
+ }
+ }
+
+ @Override
+ public void listChanged(ListChangeEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.listChanged_(event);
+ } else {
+ this.executeOnEventQueue(this.buildListChangedRunnable(event));
+ }
+ }
+
+ private Runnable buildStateChangedRunnable(final StateChangeEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.stateChanged_(event);
+ }
+ };
+ }
+
+ private Runnable buildPropertyChangedRunnable(final PropertyChangeEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.propertyChanged_(event);
+ }
+ };
+ }
+
+ private Runnable buildItemsAddedRunnable(final CollectionAddEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.itemsAdded_(event);
+ }
+ @Override
+ public String toString() {
+ return "items added runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsRemovedRunnable(final CollectionRemoveEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.itemsRemoved_(event);
+ }
+ @Override
+ public String toString() {
+ return "items removed runnable";
+ }
+ };
+ }
+
+ private Runnable buildCollectionClearedRunnable(final CollectionClearEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.collectionCleared_(event);
+ }
+ @Override
+ public String toString() {
+ return "collection cleared runnable";
+ }
+ };
+ }
+
+ private Runnable buildCollectionChangedRunnable(final CollectionChangeEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.collectionChanged_(event);
+ }
+ @Override
+ public String toString() {
+ return "collection changed runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsAddedRunnable(final ListAddEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.itemsAdded_(event);
+ }
+ @Override
+ public String toString() {
+ return "items added runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsRemovedRunnable(final ListRemoveEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.itemsRemoved_(event);
+ }
+ @Override
+ public String toString() {
+ return "items removed runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsMovedRunnable(final ListMoveEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.itemsMoved_(event);
+ }
+ @Override
+ public String toString() {
+ return "items moved runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsReplacedRunnable(final ListReplaceEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.itemsReplaced_(event);
+ }
+ @Override
+ public String toString() {
+ return "items replaced runnable";
+ }
+ };
+ }
+
+ private Runnable buildListClearedRunnable(final ListClearEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.listCleared_(event);
+ }
+ @Override
+ public String toString() {
+ return "list cleared runnable";
+ }
+ };
+ }
+
+ private Runnable buildListChangedRunnable(final ListChangeEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTChangeListenerWrapper.this.listChanged_(event);
+ }
+ @Override
+ public String toString() {
+ return "list changed runnable";
+ }
+ };
+ }
+
+ private boolean isExecutingOnUIThread() {
+ return EventQueue.isDispatchThread();
+ }
+
+ /**
+ * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+ * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+ * things more predictable when debugging, at the risk of deadlocks.
+ */
+ private void executeOnEventQueue(Runnable r) {
+ EventQueue.invokeLater(r);
+// try {
+// EventQueue.invokeAndWait(r);
+// } catch (InterruptedException ex) {
+// throw new RuntimeException(ex);
+// } catch (java.lang.reflect.InvocationTargetException ex) {
+// throw new RuntimeException(ex);
+// }
+ }
+
+ void stateChanged_(StateChangeEvent event) {
+ this.listener.stateChanged(event);
+ }
+
+ void propertyChanged_(PropertyChangeEvent event) {
+ this.listener.propertyChanged(event);
+ }
+
+ void itemsAdded_(CollectionAddEvent event) {
+ this.listener.itemsAdded(event);
+ }
+
+ void itemsRemoved_(CollectionRemoveEvent event) {
+ this.listener.itemsRemoved(event);
+ }
+
+ void collectionCleared_(CollectionClearEvent event) {
+ this.listener.collectionCleared(event);
+ }
+
+ void collectionChanged_(CollectionChangeEvent event) {
+ this.listener.collectionChanged(event);
+ }
+
+ void itemsAdded_(ListAddEvent event) {
+ this.listener.itemsAdded(event);
+ }
+
+ void itemsRemoved_(ListRemoveEvent event) {
+ this.listener.itemsRemoved(event);
+ }
+
+ void itemsMoved_(ListMoveEvent event) {
+ this.listener.itemsMoved(event);
+ }
+
+ void itemsReplaced_(ListReplaceEvent event) {
+ this.listener.itemsReplaced(event);
+ }
+
+ void listCleared_(ListClearEvent event) {
+ this.listener.listCleared(event);
+ }
+
+ void listChanged_(ListChangeEvent event) {
+ this.listener.listChanged(event);
+ }
+
+ @Override
+ public String toString() {
+ return "AWT(" + this.listener.toString() + ')';
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTCollectionChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTCollectionChangeListenerWrapper.java
new file mode 100644
index 0000000..bc7e6a8
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTCollectionChangeListenerWrapper.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.model.event.CollectionAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.listener.CollectionChangeListener;
+
+/**
+ * Wrap another collection change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited.
+ */
+@SuppressWarnings("nls")
+public final class AWTCollectionChangeListenerWrapper
+ implements CollectionChangeListener
+{
+ private final CollectionChangeListener listener;
+
+ public AWTCollectionChangeListenerWrapper(CollectionChangeListener listener) {
+ super();
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ }
+
+ @Override
+ public void itemsAdded(CollectionAddEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsAdded_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsRemoved(CollectionRemoveEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsRemoved_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
+ }
+ }
+
+ @Override
+ public void collectionCleared(CollectionClearEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.collectionCleared_(event);
+ } else {
+ this.executeOnEventQueue(this.buildCollectionClearedRunnable(event));
+ }
+ }
+
+ @Override
+ public void collectionChanged(CollectionChangeEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.collectionChanged_(event);
+ } else {
+ this.executeOnEventQueue(this.buildCollectionChangedRunnable(event));
+ }
+ }
+
+ private Runnable buildItemsAddedRunnable(final CollectionAddEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTCollectionChangeListenerWrapper.this.itemsAdded_(event);
+ }
+ @Override
+ public String toString() {
+ return "items added runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsRemovedRunnable(final CollectionRemoveEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTCollectionChangeListenerWrapper.this.itemsRemoved_(event);
+ }
+ @Override
+ public String toString() {
+ return "items removed runnable";
+ }
+ };
+ }
+
+ private Runnable buildCollectionClearedRunnable(final CollectionClearEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTCollectionChangeListenerWrapper.this.collectionCleared_(event);
+ }
+ @Override
+ public String toString() {
+ return "collection cleared runnable";
+ }
+ };
+ }
+
+ private Runnable buildCollectionChangedRunnable(final CollectionChangeEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTCollectionChangeListenerWrapper.this.collectionChanged_(event);
+ }
+ @Override
+ public String toString() {
+ return "collection changed runnable";
+ }
+ };
+ }
+
+ private boolean isExecutingOnUIThread() {
+ return EventQueue.isDispatchThread();
+ }
+
+ /**
+ * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+ * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+ * things more predictable when debugging, at the risk of deadlocks.
+ */
+ private void executeOnEventQueue(Runnable r) {
+ EventQueue.invokeLater(r);
+// try {
+// EventQueue.invokeAndWait(r);
+// } catch (InterruptedException ex) {
+// throw new RuntimeException(ex);
+// } catch (java.lang.reflect.InvocationTargetException ex) {
+// throw new RuntimeException(ex);
+// }
+ }
+
+ void itemsAdded_(CollectionAddEvent event) {
+ this.listener.itemsAdded(event);
+ }
+
+ void itemsRemoved_(CollectionRemoveEvent event) {
+ this.listener.itemsRemoved(event);
+ }
+
+ void collectionCleared_(CollectionClearEvent event) {
+ this.listener.collectionCleared(event);
+ }
+
+ void collectionChanged_(CollectionChangeEvent event) {
+ this.listener.collectionChanged(event);
+ }
+
+ @Override
+ public String toString() {
+ return "AWT(" + this.listener.toString() + ')';
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTListChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTListChangeListenerWrapper.java
new file mode 100644
index 0000000..fd57b22
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTListChangeListenerWrapper.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+
+/**
+ * Wrap another list change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited.
+ */
+@SuppressWarnings("nls")
+public final class AWTListChangeListenerWrapper
+ implements ListChangeListener
+{
+ private final ListChangeListener listener;
+
+ public AWTListChangeListenerWrapper(ListChangeListener listener) {
+ super();
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ }
+
+ @Override
+ public void itemsAdded(ListAddEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsAdded_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsRemoved_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsMoved(ListMoveEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsMoved_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsMovedRunnable(event));
+ }
+ }
+
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.itemsReplaced_(event);
+ } else {
+ this.executeOnEventQueue(this.buildItemsReplacedRunnable(event));
+ }
+ }
+
+ @Override
+ public void listCleared(ListClearEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.listCleared_(event);
+ } else {
+ this.executeOnEventQueue(this.buildListClearedRunnable(event));
+ }
+ }
+
+ @Override
+ public void listChanged(ListChangeEvent event) {
+ if (this.isExecutingOnUIThread()) {
+ this.listChanged_(event);
+ } else {
+ this.executeOnEventQueue(this.buildListChangedRunnable(event));
+ }
+ }
+
+ private Runnable buildItemsAddedRunnable(final ListAddEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTListChangeListenerWrapper.this.itemsAdded_(event);
+ }
+ @Override
+ public String toString() {
+ return "items added runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsRemovedRunnable(final ListRemoveEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTListChangeListenerWrapper.this.itemsRemoved_(event);
+ }
+ @Override
+ public String toString() {
+ return "items removed runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsMovedRunnable(final ListMoveEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTListChangeListenerWrapper.this.itemsMoved_(event);
+ }
+ @Override
+ public String toString() {
+ return "items moved runnable";
+ }
+ };
+ }
+
+ private Runnable buildItemsReplacedRunnable(final ListReplaceEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTListChangeListenerWrapper.this.itemsReplaced_(event);
+ }
+ @Override
+ public String toString() {
+ return "items replaced runnable";
+ }
+ };
+ }
+
+ private Runnable buildListClearedRunnable(final ListClearEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTListChangeListenerWrapper.this.listCleared_(event);
+ }
+ @Override
+ public String toString() {
+ return "list cleared runnable";
+ }
+ };
+ }
+
+ private Runnable buildListChangedRunnable(final ListChangeEvent event) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ AWTListChangeListenerWrapper.this.listChanged_(event);
+ }
+ @Override
+ public String toString() {
+ return "list changed runnable";
+ }
+ };
+ }
+
+ private boolean isExecutingOnUIThread() {
+ return EventQueue.isDispatchThread();
+ }
+
+ /**
+ * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+ * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+ * things more predictable when debugging, at the risk of deadlocks.
+ */
+ private void executeOnEventQueue(Runnable r) {
+ EventQueue.invokeLater(r);
+// try {
+// EventQueue.invokeAndWait(r);
+// } catch (InterruptedException ex) {
+// throw new RuntimeException(ex);
+// } catch (java.lang.reflect.InvocationTargetException ex) {
+// throw new RuntimeException(ex);
+// }
+ }
+
+ void itemsAdded_(ListAddEvent event) {
+ this.listener.itemsAdded(event);
+ }
+
+ void itemsRemoved_(ListRemoveEvent event) {
+ this.listener.itemsRemoved(event);
+ }
+
+ void itemsMoved_(ListMoveEvent event) {
+ this.listener.itemsMoved(event);
+ }
+
+ void itemsReplaced_(ListReplaceEvent event) {
+ this.listener.itemsReplaced(event);
+ }
+
+ void listCleared_(ListClearEvent event) {
+ this.listener.listCleared(event);
+ }
+
+ void listChanged_(ListChangeEvent event) {
+ this.listener.listChanged(event);
+ }
+
+ @Override
+ public String toString() {
+ return "AWT(" + this.listener.toString() + ')';
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTPropertyChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTPropertyChangeListenerWrapper.java
new file mode 100644
index 0000000..c3db685
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTPropertyChangeListenerWrapper.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.RunnableAdapter;
+import org.eclipse.persistence.tools.utility.collection.SynchronizedQueue;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+
+/**
+ * Wrap another property change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited. (Typically, the adapter(s) between a <em>property</em> and
+ * its corresponding UI widget are read-write; as opposed to the adapter(s)
+ * between a <em>collection</em> (or <em>list</em>) and its UI widget, which
+ * is read-only.)
+ * <p>
+ * Any events received earlier (on a non-UI thread) will be
+ * forwarded, in the order received, before the current event is forwarded.
+ */
+@SuppressWarnings("nls")
+public final class AWTPropertyChangeListenerWrapper
+ implements PropertyChangeListener
+{
+ private final PropertyChangeListener listener;
+ private final SynchronizedQueue<PropertyChangeEvent> events = new SynchronizedQueue<PropertyChangeEvent>();
+
+
+ public AWTPropertyChangeListenerWrapper(PropertyChangeListener listener) {
+ super();
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ }
+
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ this.events.enqueue(event);
+ if (this.isExecutingOnUIThread()) {
+ this.forwardEvents();
+ } else {
+ this.executeOnEventQueue(new ForwardEventsRunnable());
+ }
+ }
+
+ private boolean isExecutingOnUIThread() {
+ return EventQueue.isDispatchThread();
+ }
+
+ /* CU private */ class ForwardEventsRunnable
+ extends RunnableAdapter
+ {
+ @Override
+ public void run() {
+ AWTPropertyChangeListenerWrapper.this.forwardEvents();
+ }
+ }
+
+ /**
+ * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+ * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+ * things more predictable when debugging, at the risk of deadlocks.
+ */
+ private void executeOnEventQueue(Runnable r) {
+ EventQueue.invokeLater(r);
+// try {
+// EventQueue.invokeAndWait(r);
+// } catch (InterruptedException ex) {
+// throw new RuntimeException(ex);
+// } catch (java.lang.reflect.InvocationTargetException ex) {
+// throw new RuntimeException(ex);
+// }
+ }
+
+ void forwardEvents() {
+ for (PropertyChangeEvent event : this.events.drain()) {
+ this.listener.propertyChanged(event);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "AWT(" + this.listener.toString() + ')';
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTStateChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTStateChangeListenerWrapper.java
new file mode 100644
index 0000000..cc875ea
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTStateChangeListenerWrapper.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.RunnableAdapter;
+import org.eclipse.persistence.tools.utility.collection.SynchronizedQueue;
+import org.eclipse.persistence.tools.utility.model.event.StateChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.StateChangeListener;
+
+/**
+ * Wrap another state change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited.
+ * <p>
+ * Any events received earlier (on a non-UI thread) will be
+ * forwarded, in the order received, before the current event is forwarded.
+ * @see AWTPropertyChangeListenerWrapper
+ */
+@SuppressWarnings("nls")
+public final class AWTStateChangeListenerWrapper
+ implements StateChangeListener
+{
+ private final StateChangeListener listener;
+ private final SynchronizedQueue<StateChangeEvent> events = new SynchronizedQueue<StateChangeEvent>();
+
+
+ public AWTStateChangeListenerWrapper(StateChangeListener listener) {
+ super();
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ }
+
+ @Override
+ public void stateChanged(StateChangeEvent event) {
+ this.events.enqueue(event);
+ if (this.isExecutingOnUIThread()) {
+ this.forwardEvents();
+ } else {
+ this.executeOnEventQueue(new ForwardEventsRunnable());
+ }
+ }
+
+ private boolean isExecutingOnUIThread() {
+ return EventQueue.isDispatchThread();
+ }
+
+ /* CU private */ class ForwardEventsRunnable
+ extends RunnableAdapter
+ {
+ @Override
+ public void run() {
+ AWTStateChangeListenerWrapper.this.forwardEvents();
+ }
+ }
+
+ /**
+ * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+ * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+ * things more predictable when debugging, at the risk of deadlocks.
+ */
+ private void executeOnEventQueue(Runnable r) {
+ EventQueue.invokeLater(r);
+// try {
+// EventQueue.invokeAndWait(r);
+// } catch (InterruptedException ex) {
+// throw new RuntimeException(ex);
+// } catch (java.lang.reflect.InvocationTargetException ex) {
+// throw new RuntimeException(ex);
+// }
+ }
+
+ void forwardEvents() {
+ for (StateChangeEvent event : this.events.drain()) {
+ this.listener.stateChanged(event);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "AWT(" + this.listener.toString() + ')';
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/AbstractTreeModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/AbstractTreeModel.java
new file mode 100644
index 0000000..c288417
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/AbstractTreeModel.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.io.Serializable;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreeModel;
+
+/**
+ * Abstract class that should have been provided by the JDK
+ * (a la {@link javax.swing.AbstractListModel}). This class provides:<ul>
+ * <li>support for a collection of listeners
+ * <li>a number of convenience methods for firing events for those listeners
+ * </ul>
+ */
+public abstract class AbstractTreeModel
+ implements TreeModel, Serializable
+{
+ /** Our listeners. */
+ protected final EventListenerList listenerList;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors/initialization **********
+
+ protected AbstractTreeModel() {
+ super();
+ this.listenerList = new EventListenerList();
+ }
+
+
+ // ********** partial TreeModel implementation **********
+
+ @Override
+ public void addTreeModelListener(TreeModelListener l) {
+ this.listenerList.add(TreeModelListener.class, l);
+ }
+
+ @Override
+ public void removeTreeModelListener(TreeModelListener l) {
+ this.listenerList.remove(TreeModelListener.class, l);
+ }
+
+
+ // ********** queries **********
+
+ /**
+ * Return the model's current collection of listeners.
+ * (There seems to be a pattern of making this type of method public;
+ * although it should probably be protected....)
+ */
+ public TreeModelListener[] treeModelListeners() {
+ return this.listenerList.getListeners(TreeModelListener.class);
+ }
+
+ /**
+ * Return whether this model has no listeners.
+ */
+ protected boolean hasNoTreeModelListeners() {
+ return this.listenerList.getListenerCount(TreeModelListener.class) == 0;
+ }
+
+ /**
+ * Return whether this model has any listeners.
+ */
+ protected boolean hasTreeModelListeners() {
+ return ! this.hasNoTreeModelListeners();
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Notify listeners of a model change.
+ * A significant property of the nodes changed, but the nodes themselves
+ * are still the same objects.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeNodesChanged(Object[] path, int[] childIndices, Object[] children) {
+ // guaranteed to return a non-null array
+ Object[] listeners = this.listenerList.getListenerList();
+ TreeModelEvent event = null;
+ // process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==TreeModelListener.class) {
+ // lazily create the event
+ if (event == null) {
+ event = new TreeModelEvent(this, path, childIndices, children);
+ }
+ ((TreeModelListener) listeners[i+1]).treeNodesChanged(event);
+ }
+ }
+ }
+
+
+ /**
+ * Notify listeners of a model change.
+ * A significant property of the node changed, but the node itself is the same object.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeNodeChanged(Object[] path, int childIndex, Object child) {
+ this.fireTreeNodesChanged(path, new int[] {childIndex}, new Object[] {child});
+ }
+
+ /**
+ * Notify listeners of a model change.
+ * A significant property of the root changed, but the root itself is the same object.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeRootChanged(Object root) {
+ this.fireTreeNodesChanged(new Object[] {root}, null, null);
+ }
+
+ /**
+ * Notify listeners of a model change.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeNodesInserted(Object[] path, int[] childIndices, Object[] children) {
+ // guaranteed to return a non-null array
+ Object[] listeners = this.listenerList.getListenerList();
+ TreeModelEvent event = null;
+ // process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==TreeModelListener.class) {
+ // lazily create the event
+ if (event == null) {
+ event = new TreeModelEvent(this, path, childIndices, children);
+ }
+ ((TreeModelListener) listeners[i+1]).treeNodesInserted(event);
+ }
+ }
+ }
+
+ /**
+ * Notify listeners of a model change.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeNodeInserted(Object[] path, int childIndex, Object child) {
+ this.fireTreeNodesInserted(path, new int[] {childIndex}, new Object[] {child});
+ }
+
+ /**
+ * Notify listeners of a model change.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeNodesRemoved(Object[] path, int[] childIndices, Object[] children) {
+ // guaranteed to return a non-null array
+ Object[] listeners = this.listenerList.getListenerList();
+ TreeModelEvent event = null;
+ // process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==TreeModelListener.class) {
+ // lazily create the event
+ if (event == null) {
+ event = new TreeModelEvent(this, path, childIndices, children);
+ }
+ ((TreeModelListener) listeners[i+1]).treeNodesRemoved(event);
+ }
+ }
+ }
+
+ /**
+ * Notify listeners of a model change.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeNodeRemoved(Object[] path, int childIndex, Object child) {
+ this.fireTreeNodesRemoved(path, new int[] {childIndex}, new Object[] {child});
+ }
+
+ /**
+ * Notify listeners of a model change.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeStructureChanged(Object[] path) {
+ // guaranteed to return a non-null array
+ Object[] listeners = this.listenerList.getListenerList();
+ TreeModelEvent event = null;
+ // process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==TreeModelListener.class) {
+ // lazily create the event
+ if (event == null) {
+ event = new TreeModelEvent(this, path);
+ }
+ ((TreeModelListener) listeners[i+1]).treeStructureChanged(event);
+ }
+ }
+ }
+
+ /**
+ * Notify listeners of a model change.
+ * @see javax.swing.event.TreeModelEvent
+ * @see javax.swing.event.TreeModelListener
+ */
+ protected void fireTreeRootReplaced(Object newRoot) {
+ this.fireTreeStructureChanged(new Object[] {newRoot});
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/CheckBoxModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/CheckBoxModelAdapter.java
new file mode 100644
index 0000000..e39c77a
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/CheckBoxModelAdapter.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+
+/**
+ * This javax.swing.ButtonModel can be used to keep a listener
+ * (e.g. a JCheckBox) in synch with a PropertyValueModel that
+ * holds a boolean.
+ *
+ * Maybe not the richest class in our toolbox, but it was the
+ * victim of refactoring.... ~bjv
+ */
+public class CheckBoxModelAdapter
+ extends ToggleButtonModelAdapter
+{
+ private static final long serialVersionUID = 1L;
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the boolean holder is required.
+ */
+ public CheckBoxModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder, boolean defaultValue) {
+ super(booleanHolder, defaultValue);
+ }
+
+ /**
+ * Constructor - the boolean holder is required.
+ * The default value will be false.
+ */
+ public CheckBoxModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder) {
+ super(booleanHolder);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ComboBoxModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ComboBoxModelAdapter.java
new file mode 100644
index 0000000..e8add59
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ComboBoxModelAdapter.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import javax.swing.ComboBoxModel;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.ComboBoxModel can be used to keep a ListDataListener
+ * (e.g. a JComboBox) in synch with a ListValueModel (or a CollectionValueModel).
+ * For combo boxes, the model object that holds the current selection is
+ * typically a different model object than the one that holds the collection
+ * of choices.
+ *
+ * For example, a MWReference (the selectionOwner) has an attribute
+ * "sourceTable" (the collectionOwner)
+ * which holds on to a collection of MWDatabaseFields. When the selection
+ * is changed this model will keep the listeners aware of the changes.
+ * The inherited list model will keep its listeners aware of changes to the
+ * collection model
+ *
+ * In addition to the collection holder required by the superclass,
+ * an instance of this ComboBoxModel must be supplied with a
+ * selection holder, which is a PropertyValueModel that provides access
+ * to the selection (typically a PropertyAspectAdapter).
+ */
+@SuppressWarnings("nls")
+public class ComboBoxModelAdapter
+ extends ListModelAdapter
+ implements ComboBoxModel
+{
+ protected final ModifiablePropertyValueModel<Object> selectionHolder;
+ protected final PropertyChangeListener selectionListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the list holder and selection holder are required;
+ */
+ public ComboBoxModelAdapter(ListValueModel<?> listHolder, ModifiablePropertyValueModel<Object> selectionHolder) {
+ super(listHolder);
+ if (selectionHolder == null) {
+ throw new NullPointerException();
+ }
+ this.selectionHolder = selectionHolder;
+ this.selectionListener = this.buildSelectionListener();
+ }
+
+ /**
+ * Constructor - the collection holder and selection holder are required;
+ */
+ public ComboBoxModelAdapter(CollectionValueModel<?> collectionHolder, ModifiablePropertyValueModel<Object> selectionHolder) {
+ super(collectionHolder);
+ if (selectionHolder == null) {
+ throw new NullPointerException();
+ }
+ this.selectionHolder = selectionHolder;
+ this.selectionListener = this.buildSelectionListener();
+ }
+
+
+ // ********** initialization **********
+
+ protected PropertyChangeListener buildSelectionListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildSelectionListener_());
+ }
+
+ protected PropertyChangeListener buildSelectionListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ // notify listeners that the selection has changed
+ ComboBoxModelAdapter.this.fireSelectionChanged();
+ }
+ @Override
+ public String toString() {
+ return "selection listener";
+ }
+ };
+ }
+
+
+ // ********** ComboBoxModel implementation **********
+
+ @Override
+ public Object getSelectedItem() {
+ return this.selectionHolder.getValue();
+ }
+
+ @Override
+ public void setSelectedItem(Object selectedItem) {
+ this.selectionHolder.setValue(selectedItem);
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Extend to engage the selection holder.
+ */
+ @Override
+ protected void engageModel() {
+ super.engageModel();
+ this.selectionHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.selectionListener);
+ }
+
+ /**
+ * Extend to disengage the selection holder.
+ */
+ @Override
+ protected void disengageModel() {
+ this.selectionHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.selectionListener);
+ super.disengageModel();
+ }
+
+ /**
+ * Notify the listeners that the selection has changed.
+ */
+ protected void fireSelectionChanged() {
+ // I guess this will work...
+ this.fireContentsChanged(this, -1, -1);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.selectionHolder + ":" + this.listHolder);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DateSpinnerModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DateSpinnerModelAdapter.java
new file mode 100644
index 0000000..bb8822f
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DateSpinnerModelAdapter.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.Calendar;
+import java.util.Date;
+import javax.swing.SpinnerDateModel;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.SpinnerDateModel can be used to keep a ChangeListener
+ * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a date.
+ *
+ * This class must be a sub-class of SpinnerDateModel because of some
+ * crappy jdk code.... ~bjv
+ * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
+ *
+ * If this class needs to be modified, it would behoove us to review the
+ * other, similar classes:
+ * @see ListSpinnerModelAdapter
+ * @see NumberSpinnerModelAdapter
+ */
+@SuppressWarnings("nls")
+public class DateSpinnerModelAdapter
+ extends SpinnerDateModel
+{
+ /**
+ * The default spinner value; used when the underlying model date value is null.
+ * The default is the current date.
+ */
+ private final Date defaultValue;
+
+ /** A value model on the underlying date. */
+ private final ModifiablePropertyValueModel<Object> dateHolder;
+
+ /** A listener that allows us to synchronize with changes made to the underlying date. */
+ private final PropertyChangeListener dateChangeListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the date holder is required.
+ * The default spinner value is the current date.
+ */
+ public DateSpinnerModelAdapter(ModifiablePropertyValueModel<Object> dateHolder) {
+ this(dateHolder, new Date());
+ }
+
+ /**
+ * Constructor - the date holder and default value are required.
+ */
+ public DateSpinnerModelAdapter(ModifiablePropertyValueModel<Object> dateHolder, Date defaultValue) {
+ this(dateHolder, null, null, Calendar.DAY_OF_MONTH, defaultValue);
+ }
+
+ /**
+ * Constructor - the date holder is required.
+ * The default spinner value is the current date.
+ */
+ public DateSpinnerModelAdapter(ModifiablePropertyValueModel<Object> dateHolder, Comparable<?> start, Comparable<?> end, int calendarField) {
+ this(dateHolder, start, end, calendarField, new Date());
+ }
+
+ /**
+ * Constructor - the date holder is required.
+ */
+ public DateSpinnerModelAdapter(ModifiablePropertyValueModel<Object> dateHolder, Comparable<?> start, Comparable<?> end, int calendarField, Date defaultValue) {
+ super(dateHolder.getValue() == null ? defaultValue : (Date) dateHolder.getValue(), start, end, calendarField);
+ this.dateHolder = dateHolder;
+ this.dateChangeListener = this.buildDateChangeListener();
+ // postpone listening to the underlying date
+ // until we have listeners ourselves...
+ this.defaultValue = defaultValue;
+ }
+
+
+ // ********** initialization **********
+
+ protected PropertyChangeListener buildDateChangeListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildDateChangeListener_());
+ }
+
+ protected PropertyChangeListener buildDateChangeListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ DateSpinnerModelAdapter.this.synchronize(event.getNewValue());
+ }
+ @Override
+ public String toString() {
+ return "date listener";
+ }
+ };
+ }
+
+
+ // ********** SpinnerModel implementation **********
+
+ /**
+ * Extend to check whether this method is being called before we
+ * have any listeners.
+ * This is necessary because some crappy jdk code gets the value
+ * from the model *before* listening to the model. ~bjv
+ * @see javax.swing.JSpinner.DefaultEditor#DefaultEditor(javax.swing.JSpinner)
+ */
+ @Override
+ public Object getValue() {
+ if (this.getChangeListeners().length == 0) {
+ // sorry about this "lateral" call to super ~bjv
+ super.setValue(this.spinnerValueOf(this.dateHolder.getValue()));
+ }
+ return super.getValue();
+ }
+
+ /**
+ * Extend to update the underlying date directly.
+ * The resulting event will be ignored: @see #synchronize(Object).
+ */
+ @Override
+ public void setValue(Object value) {
+ super.setValue(value);
+ this.dateHolder.setValue(value);
+ }
+
+ /**
+ * Extend to start listening to the underlying date if necessary.
+ */
+ @Override
+ public void addChangeListener(ChangeListener listener) {
+ if (this.getChangeListeners().length == 0) {
+ this.dateHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.dateChangeListener);
+ this.synchronize(this.dateHolder.getValue());
+ }
+ super.addChangeListener(listener);
+ }
+
+ /**
+ * Extend to stop listening to the underlying date if appropriate.
+ */
+ @Override
+ public void removeChangeListener(ChangeListener listener) {
+ super.removeChangeListener(listener);
+ if (this.getChangeListeners().length == 0) {
+ this.dateHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.dateChangeListener);
+ }
+ }
+
+
+ // ********** queries **********
+
+ protected Date getDefaultValue() {
+ return this.defaultValue;
+ }
+
+ /**
+ * Convert to a non-null value.
+ */
+ protected Object spinnerValueOf(Object value) {
+ return (value == null) ? this.getDefaultValue() : value;
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Set the spinner value if it has changed.
+ */
+ void synchronize(Object value) {
+ Object newValue = this.spinnerValueOf(value);
+ // check to see whether the spinner date has already been synchronized
+ // (via #setValue())
+ if ( ! this.getValue().equals(newValue)) {
+ this.setValue(newValue);
+ }
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.dateHolder);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DocumentAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DocumentAdapter.java
new file mode 100644
index 0000000..63c60d4
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DocumentAdapter.java
@@ -0,0 +1,405 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.EventObject;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.Position;
+import javax.swing.text.Segment;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.text.Document can be used to keep a DocumentListener
+ * (e.g. a JTextField) in synch with a PropertyValueModel that holds a string.
+ *
+ * NB: This model should only be used for "small" documents;
+ * i.e. documents used by text fields, not text panes.
+ * @see #synchronizeDelegate(String)
+ */
+@SuppressWarnings("nls")
+public class DocumentAdapter
+ implements Document, Serializable
+{
+ /** The delegate document whose behavior we "enhance". */
+ protected final Document delegate;
+
+ /** A listener that allows us to forward any changes made to the delegate document. */
+ protected final CombinedListener delegateListener;
+
+ /** A value model on the underlying model string. */
+ protected final ModifiablePropertyValueModel<String> stringHolder;
+
+ /** A listener that allows us to synchronize with changes made to the underlying model string. */
+ protected transient PropertyChangeListener stringListener;
+
+ /** The event listener list for the document. */
+ protected final EventListenerList listenerList = new EventListenerList();
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the string holder is required.
+ * Wrap the specified document.
+ */
+ public DocumentAdapter(ModifiablePropertyValueModel<String> stringHolder, Document delegate) {
+ super();
+ if (stringHolder == null || delegate == null) {
+ throw new NullPointerException();
+ }
+ this.stringHolder = stringHolder;
+ // postpone listening to the underlying model string
+ // until we have listeners ourselves...
+ this.delegate = delegate;
+ this.stringListener = this.buildStringListener();
+ this.delegateListener = this.buildDelegateListener();
+ }
+
+ /**
+ * Constructor - the string holder is required.
+ * Wrap a plain document.
+ */
+ public DocumentAdapter(ModifiablePropertyValueModel<String> stringHolder) {
+ this(stringHolder, new PlainDocument());
+ }
+
+
+ // ********** initialization **********
+
+ protected PropertyChangeListener buildStringListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildStringListener_());
+ }
+
+ protected PropertyChangeListener buildStringListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ DocumentAdapter.this.stringChanged(event);
+ }
+ @Override
+ public String toString() {
+ return "string listener";
+ }
+ };
+ }
+
+ protected CombinedListener buildDelegateListener() {
+ return new InternalListener();
+ }
+
+
+ // ********** Document implementation **********
+
+ @Override
+ public int getLength() {
+ return this.delegate.getLength();
+ }
+
+ /**
+ * Extend to start listening to the underlying models if necessary.
+ */
+ @Override
+ public void addDocumentListener(DocumentListener listener) {
+ if (this.listenerList.getListenerCount(DocumentListener.class) == 0) {
+ this.delegate.addDocumentListener(this.delegateListener);
+ this.engageStringHolder();
+ }
+ this.listenerList.add(DocumentListener.class, listener);
+ }
+
+ /**
+ * Extend to stop listening to the underlying models if appropriate.
+ */
+ @Override
+ public void removeDocumentListener(DocumentListener listener) {
+ this.listenerList.remove(DocumentListener.class, listener);
+ if (this.listenerList.getListenerCount(DocumentListener.class) == 0) {
+ this.disengageStringHolder();
+ this.delegate.removeDocumentListener(this.delegateListener);
+ }
+ }
+
+ /**
+ * Extend to start listening to the delegate document if necessary.
+ */
+ @Override
+ public void addUndoableEditListener(UndoableEditListener listener) {
+ if (this.listenerList.getListenerCount(UndoableEditListener.class) == 0) {
+ this.delegate.addUndoableEditListener(this.delegateListener);
+ }
+ this.listenerList.add(UndoableEditListener.class, listener);
+ }
+
+ /**
+ * Extend to stop listening to the delegate document if appropriate.
+ */
+ @Override
+ public void removeUndoableEditListener(UndoableEditListener listener) {
+ this.listenerList.remove(UndoableEditListener.class, listener);
+ if (this.listenerList.getListenerCount(UndoableEditListener.class) == 0) {
+ this.delegate.removeUndoableEditListener(this.delegateListener);
+ }
+ }
+
+ @Override
+ public Object getProperty(Object key) {
+ return this.delegate.getProperty(key);
+ }
+
+ @Override
+ public void putProperty(Object key, Object value) {
+ this.delegate.putProperty(key, value);
+ }
+
+ /**
+ * Extend to update the underlying model string directly.
+ * The resulting event will be ignored: @see #synchronizeDelegate(String).
+ */
+ @Override
+ public void remove(int offset, int len) throws BadLocationException {
+ this.delegate.remove(offset, len);
+ this.stringHolder.setValue(this.delegate.getText(0, this.delegate.getLength()));
+ }
+
+ /**
+ * Extend to update the underlying model string directly.
+ * The resulting event will be ignored: @see #synchronizeDelegate(String).
+ */
+ @Override
+ public void insertString(int offset, String insertedString, AttributeSet a) throws BadLocationException {
+ this.delegate.insertString(offset, insertedString, a);
+ this.stringHolder.setValue(this.delegate.getText(0, this.delegate.getLength()));
+ }
+
+ @Override
+ public String getText(int offset, int length) throws BadLocationException {
+ return this.delegate.getText(offset, length);
+ }
+
+ @Override
+ public void getText(int offset, int length, Segment txt) throws BadLocationException {
+ this.delegate.getText(offset, length, txt);
+ }
+
+ @Override
+ public Position getStartPosition() {
+ return this.delegate.getStartPosition();
+ }
+
+ @Override
+ public Position getEndPosition() {
+ return this.delegate.getEndPosition();
+ }
+
+ @Override
+ public Position createPosition(int offs) throws BadLocationException {
+ return this.delegate.createPosition(offs);
+ }
+
+ @Override
+ public Element[] getRootElements() {
+ return this.delegate.getRootElements();
+ }
+
+ @Override
+ public Element getDefaultRootElement() {
+ return this.delegate.getDefaultRootElement();
+ }
+
+ @Override
+ public void render(Runnable r) {
+ this.delegate.render(r);
+ }
+
+
+ // ********** queries **********
+
+ public DocumentListener[] documentListeners() {
+ return this.listenerList.getListeners(DocumentListener.class);
+ }
+
+ public UndoableEditListener[] undoableEditListeners() {
+ return this.listenerList.getListeners(UndoableEditListener.class);
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * A third party has modified the underlying model string.
+ * Synchronize the delegate document accordingly.
+ */
+ protected void stringChanged(PropertyChangeEvent event) {
+ this.synchronizeDelegate((String) event.getNewValue());
+ }
+
+ /**
+ * Replace the document's entire text string with the new string.
+ */
+ protected void synchronizeDelegate(String s) {
+ try {
+ int len = this.delegate.getLength();
+ // check to see whether the delegate has already been synchronized
+ // (via #insertString() or #remove())
+ if ( ! this.delegate.getText(0, len).equals(s)) {
+ this.delegate.remove(0, len);
+ this.delegate.insertString(0, s, null);
+ }
+ } catch (BadLocationException ex) {
+ throw new IllegalStateException(ex.getMessage()); // this should not happen...
+ }
+ }
+
+ protected void engageStringHolder() {
+ this.stringHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.stringListener);
+ this.synchronizeDelegate(this.stringHolder.getValue());
+ }
+
+ protected void disengageStringHolder() {
+ this.stringHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.stringListener);
+ }
+
+ protected void delegateChangedUpdate(DocumentEvent event) {
+ // no need to lazy-initialize the event;
+ // we wouldn't get here if we did not have listeners...
+ DocumentEvent ee = new InternalDocumentEvent(this, event);
+ DocumentListener[] listeners = this.documentListeners();
+ for (int i = listeners.length; i-- > 0; ) {
+ listeners[i].changedUpdate(ee);
+ }
+ }
+
+ protected void delegateInsertUpdate(DocumentEvent event) {
+ // no need to lazy-initialize the event;
+ // we wouldn't get here if we did not have listeners...
+ DocumentEvent ee = new InternalDocumentEvent(this, event);
+ DocumentListener[] listeners = this.documentListeners();
+ for (int i = listeners.length; i-- > 0; ) {
+ listeners[i].insertUpdate(ee);
+ }
+ }
+
+ protected void delegateRemoveUpdate(DocumentEvent event) {
+ // no need to lazy-initialize the event;
+ // we wouldn't get here if we did not have listeners...
+ DocumentEvent ee = new InternalDocumentEvent(this, event);
+ DocumentListener[] listeners = this.documentListeners();
+ for (int i = listeners.length; i-- > 0; ) {
+ listeners[i].removeUpdate(ee);
+ }
+ }
+
+ protected void delegateUndoableEditHappened(UndoableEditEvent event) {
+ // no need to lazy-initialize the event;
+ // we wouldn't get here if we did not have listeners...
+ UndoableEditEvent ee = new UndoableEditEvent(this, event.getEdit());
+ UndoableEditListener[] listeners = this.undoableEditListeners();
+ for (int i = listeners.length; i-- > 0; ) {
+ listeners[i].undoableEditHappened(ee);
+ }
+ }
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.stringHolder);
+ }
+
+ private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
+ // read in any hidden stuff
+ s.defaultReadObject();
+ this.stringListener = this.buildStringListener();
+ }
+
+
+// ********** inner class **********
+
+ protected interface CombinedListener extends DocumentListener, UndoableEditListener, Serializable {
+ // just consolidate the two interfaces
+ }
+
+ protected class InternalListener implements CombinedListener {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public void changedUpdate(DocumentEvent event) {
+ DocumentAdapter.this.delegateChangedUpdate(event);
+ }
+ @Override
+ public void insertUpdate(DocumentEvent event) {
+ DocumentAdapter.this.delegateInsertUpdate(event);
+ }
+ @Override
+ public void removeUpdate(DocumentEvent event) {
+ DocumentAdapter.this.delegateRemoveUpdate(event);
+ }
+ @Override
+ public void undoableEditHappened(UndoableEditEvent event) {
+ DocumentAdapter.this.delegateUndoableEditHappened(event);
+ }
+ }
+
+ protected static class InternalDocumentEvent
+ extends EventObject
+ implements DocumentEvent
+ {
+ protected DocumentEvent delegate;
+
+ private static final long serialVersionUID = 1L;
+
+ protected InternalDocumentEvent(Document document, DocumentEvent delegate) {
+ super(document);
+ this.delegate = delegate;
+ }
+ @Override
+ public ElementChange getChange(Element elem) {
+ return this.delegate.getChange(elem);
+ }
+ @Override
+ public Document getDocument() {
+ return (Document) this.source;
+ }
+ @Override
+ public int getLength() {
+ return this.delegate.getLength();
+ }
+ @Override
+ public int getOffset() {
+ return this.delegate.getOffset();
+ }
+ @Override
+ public EventType getType() {
+ return this.delegate.getType();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListModelAdapter.java
new file mode 100644
index 0000000..b1089b1
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListModelAdapter.java
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import javax.swing.AbstractListModel;
+import javax.swing.event.ListDataListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTListChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.CollectionListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+
+/**
+ * This javax.swing.ListModel can be used to keep a ListDataListener
+ * (e.g. a JList) in synch with a ListValueModel (or a CollectionValueModel).
+ *
+ * An instance of this ListModel *must* be supplied with a value model,
+ * which is a ListValueModel on the bound list or a CollectionValueModel
+ * on the bound collection. This is required - the list (or collection)
+ * itself can be null, but the value model that holds it cannot.
+ */
+@SuppressWarnings("nls")
+public class ListModelAdapter
+ extends AbstractListModel
+{
+ /** A value model on the underlying model list. */
+ protected ListValueModel<?> listHolder;
+
+ /**
+ * Cache the size of the list for "dramatic" changes.
+ * @see #listChanged()
+ */
+ protected int listSize;
+
+ /** A listener that allows us to forward changes made to the underlying model list. */
+ protected final ListChangeListener listChangeListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Default constructor - initialize stuff.
+ */
+ private ListModelAdapter() {
+ super();
+ this.listSize = 0;
+ this.listChangeListener = this.buildListChangeListener();
+ }
+
+ /**
+ * Constructor - the list holder is required.
+ */
+ public ListModelAdapter(ListValueModel<?> listHolder) {
+ this();
+ this.setModel(listHolder);
+ }
+
+ /**
+ * Constructor - the collection holder is required.
+ */
+ public ListModelAdapter(CollectionValueModel<?> collectionHolder) {
+ this();
+ this.setModel(collectionHolder);
+ }
+
+
+ // ********** initialization **********
+
+ protected ListChangeListener buildListChangeListener() {
+ return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
+ }
+
+ protected ListChangeListener buildListChangeListener_() {
+ return new ListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) {
+ ListModelAdapter.this.itemsAdded(event);
+ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {
+ ListModelAdapter.this.itemsRemoved(event);
+ }
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {
+ ListModelAdapter.this.itemsReplaced(event);
+ }
+ @Override
+ public void itemsMoved(ListMoveEvent event) {
+ ListModelAdapter.this.itemsMoved(event);
+ }
+ @Override
+ public void listCleared(ListClearEvent event) {
+ ListModelAdapter.this.listCleared();
+ }
+ @Override
+ public void listChanged(ListChangeEvent event) {
+ ListModelAdapter.this.listChanged();
+ }
+ @Override
+ public String toString() {
+ return "list listener";
+ }
+ };
+ }
+
+
+ // ********** ListModel implementation **********
+
+ @Override
+ public int getSize() {
+ return this.listHolder.size();
+ }
+
+ @Override
+ public Object getElementAt(int index) {
+ return this.listHolder.get(index);
+ }
+
+ /**
+ * Extend to start listening to the underlying model list if necessary.
+ */
+ @Override
+ public void addListDataListener(ListDataListener l) {
+ if (this.hasNoListDataListeners()) {
+ this.engageModel();
+ this.listSize = this.listHolder.size();
+ }
+ super.addListDataListener(l);
+ }
+
+ /**
+ * Extend to stop listening to the underlying model list if appropriate.
+ */
+ @Override
+ public void removeListDataListener(ListDataListener l) {
+ super.removeListDataListener(l);
+ if (this.hasNoListDataListeners()) {
+ this.disengageModel();
+ this.listSize = 0;
+ }
+ }
+
+
+ // ********** public API **********
+
+ /**
+ * Return the underlying list model.
+ */
+ public ListValueModel<?> model() {
+ return this.listHolder;
+ }
+
+ /**
+ * Set the underlying list model.
+ */
+ public void setModel(ListValueModel<?> listHolder) {
+ if (listHolder == null) {
+ throw new NullPointerException();
+ }
+ boolean hasListeners = this.hasListDataListeners();
+ if (hasListeners) {
+ this.disengageModel();
+ }
+ this.listHolder = listHolder;
+ if (hasListeners) {
+ this.engageModel();
+ this.listChanged();
+ }
+ }
+
+ /**
+ * Set the underlying collection model.
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void setModel(CollectionValueModel<?> collectionHolder) {
+ this.setModel(new CollectionListValueModelAdapter(collectionHolder));
+ }
+
+
+ // ********** queries **********
+
+ /**
+ * Return whether this model has no listeners.
+ */
+ protected boolean hasNoListDataListeners() {
+ return this.getListDataListeners().length == 0;
+ }
+
+ /**
+ * Return whether this model has any listeners.
+ */
+ protected boolean hasListDataListeners() {
+ return ! this.hasNoListDataListeners();
+ }
+
+
+ // ********** behavior **********
+
+ protected void engageModel() {
+ this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+ }
+
+ protected void disengageModel() {
+ this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+ }
+
+
+
+ // ********** list change support **********
+
+ /**
+ * Items were added to the underlying model list.
+ * Notify listeners of the changes.
+ */
+ protected void itemsAdded(ListAddEvent event) {
+ int start = event.getIndex();
+ int end = start + event.getItemsSize() - 1;
+ this.fireIntervalAdded(this, start, end);
+ this.listSize += event.getItemsSize();
+ }
+
+ /**
+ * Items were removed from the underlying model list.
+ * Notify listeners of the changes.
+ */
+ protected void itemsRemoved(ListRemoveEvent event) {
+ int start = event.getIndex();
+ int end = start + event.getItemsSize() - 1;
+ this.fireIntervalRemoved(this, start, end);
+ this.listSize -= event.getItemsSize();
+ }
+
+ /**
+ * Items were replaced in the underlying model list.
+ * Notify listeners of the changes.
+ */
+ protected void itemsReplaced(ListReplaceEvent event) {
+ int start = event.getIndex();
+ int end = start + event.getItemsSize() - 1;
+ this.fireContentsChanged(this, start, end);
+ }
+
+ /**
+ * Items were moved in the underlying model list.
+ * Notify listeners of the changes.
+ */
+ protected void itemsMoved(ListMoveEvent event) {
+ int start = Math.min(event.getSourceIndex(), event.getTargetIndex());
+ int end = Math.max(event.getSourceIndex(), event.getTargetIndex()) + event.getLength() - 1;
+ this.fireContentsChanged(this, start, end);
+ }
+
+ /**
+ * The underlying model list was cleared.
+ * Notify listeners of the changes.
+ */
+ protected void listCleared() {
+ if (this.listSize != 0) {
+ this.fireIntervalRemoved(this, 0, this.listSize - 1);
+ this.listSize = 0;
+ }
+ }
+
+ /**
+ * The underlying model list has changed "dramatically".
+ * Notify listeners of the changes.
+ */
+ protected void listChanged() {
+ if (this.listSize != 0) {
+ this.fireIntervalRemoved(this, 0, this.listSize - 1);
+ }
+ this.listSize = this.listHolder.size();
+ if (this.listSize != 0) {
+ this.fireIntervalAdded(this, 0, this.listSize - 1);
+ }
+ }
+
+
+ // ********** Object overrides **********
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.listHolder);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListSpinnerModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListSpinnerModelAdapter.java
new file mode 100644
index 0000000..37cc11e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListSpinnerModelAdapter.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.swing.SpinnerListModel;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.SpinnerListModel can be used to keep a ChangeListener
+ * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a value
+ * in the list.
+ *
+ * This class must be a sub-class of SpinnerListModel because of some
+ * crappy jdk code.... ~bjv
+ * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
+ *
+ * NB: This model should only be used for values that have a reasonably
+ * inexpensive #equals() implementation.
+ * @see #synchronize(Object)
+ *
+ * If this class needs to be modified, it would behoove us to review the
+ * other, similar classes:
+ * @see DateSpinnerModelAdapter
+ * @see NumberSpinnerModelAdapter
+ */
+@SuppressWarnings("nls")
+public class ListSpinnerModelAdapter
+ extends SpinnerListModel
+{
+ /**
+ * The default spinner value; used when the underlying model value is null.
+ * The default is the first item on the list.
+ */
+ private final Object defaultValue;
+
+ /** A value model on the underlying value. */
+ private final ModifiablePropertyValueModel<Object> valueHolder;
+
+ /** A listener that allows us to synchronize with changes made to the underlying value. */
+ private final PropertyChangeListener valueChangeListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the value holder is required.
+ * Use the model value itself as the default spinner value.
+ */
+ public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder) {
+ this(valueHolder, valueHolder.getValue());
+ }
+
+ /**
+ * Constructor - the value holder is required.
+ */
+ public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object defaultValue) {
+ this(valueHolder, new Object[] {defaultValue}, defaultValue);
+ }
+
+ /**
+ * Constructor - the value holder is required.
+ * Use the first item in the list of values as the default spinner value.
+ */
+ public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object[] values) {
+ this(valueHolder, values, values[0]);
+ }
+
+ /**
+ * Constructor - the value holder is required.
+ */
+ public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object[] values, Object defaultValue) {
+ this(valueHolder, Arrays.asList(values), defaultValue);
+ }
+
+ /**
+ * Constructor - the value holder is required.
+ * Use the first item in the list of values as the default spinner value.
+ */
+ public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, List<Object> values) {
+ this(valueHolder, values, values.get(0));
+ }
+
+ /**
+ * Constructor - the value holder is required.
+ */
+ public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, List<Object> values, Object defaultValue) {
+ super(values);
+ this.valueHolder = valueHolder;
+ this.valueChangeListener = this.buildValueChangeListener();
+ // postpone listening to the underlying value
+ // until we have listeners ourselves...
+ this.defaultValue = defaultValue;
+ }
+
+
+ // ********** initialization **********
+
+ protected PropertyChangeListener buildValueChangeListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildValueChangeListener_());
+ }
+
+ protected PropertyChangeListener buildValueChangeListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ ListSpinnerModelAdapter.this.synchronize(event.getNewValue());
+ }
+ @Override
+ public String toString() {
+ return "value listener";
+ }
+ };
+ }
+
+
+ // ********** SpinnerModel implementation **********
+
+ /**
+ * Extend to check whether this method is being called before we
+ * have any listeners.
+ * This is necessary because some crappy jdk code gets the value
+ * from the model *before* listening to the model. ~bjv
+ * @see javax.swing.JSpinner.DefaultEditor#DefaultEditor(javax.swing.JSpinner)
+ */
+ @Override
+ public Object getValue() {
+ if (this.getChangeListeners().length == 0) {
+ // sorry about this "lateral" call to super ~bjv
+ super.setValue(this.spinnerValueOf(this.valueHolder.getValue()));
+ }
+ return super.getValue();
+ }
+
+ /**
+ * Extend to update the underlying value directly.
+ * The resulting event will be ignored: @see #synchronize(Object).
+ */
+ @Override
+ public void setValue(Object value) {
+ super.setValue(value);
+ this.valueHolder.setValue(value);
+ }
+
+ /**
+ * Extend to start listening to the underlying value if necessary.
+ */
+ @Override
+ public void addChangeListener(ChangeListener listener) {
+ if (this.getChangeListeners().length == 0) {
+ this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener);
+ this.synchronize(this.valueHolder.getValue());
+ }
+ super.addChangeListener(listener);
+ }
+
+ /**
+ * Extend to stop listening to the underlying value if appropriate.
+ */
+ @Override
+ public void removeChangeListener(ChangeListener listener) {
+ super.removeChangeListener(listener);
+ if (this.getChangeListeners().length == 0) {
+ this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener);
+ }
+ }
+
+
+ // ********** queries **********
+
+ protected Object getDefaultValue() {
+ return this.defaultValue;
+ }
+
+ /**
+ * Convert to a non-null value.
+ */
+ protected Object spinnerValueOf(Object value) {
+ return (value == null) ? this.getDefaultValue() : value;
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Set the spinner value if it has changed.
+ */
+ void synchronize(Object value) {
+ Object newValue = this.spinnerValueOf(value);
+ // check to see whether the spinner value has already been synchronized
+ // (via #setValue())
+ if ( ! this.getValue().equals(newValue)) {
+ this.setValue(newValue);
+ }
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.valueHolder);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/NumberSpinnerModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/NumberSpinnerModelAdapter.java
new file mode 100644
index 0000000..366c2dc
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/NumberSpinnerModelAdapter.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.SpinnerNumberModel can be used to keep a ChangeListener
+ * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a number.
+ *
+ * This class must be a sub-class of SpinnerNumberModel because of some
+ * crappy jdk code.... ~bjv
+ * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
+ *
+ * If this class needs to be modified, it would behoove us to review the
+ * other, similar classes:
+ * @see DateSpinnerModelAdapter
+ * @see ListSpinnerModelAdapter
+ */
+@SuppressWarnings("nls")
+public class NumberSpinnerModelAdapter
+ extends SpinnerNumberModel
+{
+ /**
+ * The default spinner value; used when the
+ * underlying model number value is null.
+ */
+ private final Number defaultValue;
+
+ /** A value model on the underlying number. */
+ private final ModifiablePropertyValueModel<Number> numberHolder;
+
+ /**
+ * A listener that allows us to synchronize with
+ * changes made to the underlying number.
+ */
+ private final PropertyChangeListener numberChangeListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the number holder is required.
+ * The default spinner value is zero.
+ * The step size is one.
+ */
+ public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder) {
+ this(numberHolder, 0);
+ }
+
+ /**
+ * Constructor - the number holder is required.
+ * The step size is one.
+ */
+ public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, int defaultValue) {
+ this(numberHolder, null, null, Integer.valueOf(1), Integer.valueOf(defaultValue));
+ }
+
+ /**
+ * Constructor - the number holder is required.
+ * Use the minimum value as the default spinner value.
+ */
+ public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, int minimum, int maximum, int stepSize) {
+ this(numberHolder, minimum, maximum, stepSize, minimum);
+ }
+
+ /**
+ * Constructor - the number holder is required.
+ */
+ public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, int minimum, int maximum, int stepSize, int defaultValue) {
+ this(numberHolder, Integer.valueOf(minimum), Integer.valueOf(maximum), Integer.valueOf(stepSize), Integer.valueOf(defaultValue));
+ }
+
+ /**
+ * Constructor - the number holder is required.
+ * Use the minimum value as the default spinner value.
+ */
+ public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, double minimum, double maximum, double stepSize) {
+ this(numberHolder, minimum, maximum, stepSize, minimum);
+ }
+
+ /**
+ * Constructor - the number holder is required.
+ */
+ public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, double minimum, double maximum, double stepSize, double defaultValue) {
+ this(numberHolder, Double.valueOf(minimum), Double.valueOf(maximum), Double.valueOf(stepSize), Double.valueOf(defaultValue));
+ }
+
+ /**
+ * Constructor - the number holder is required.
+ */
+ public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, Comparable<?> minimum, Comparable<?> maximum, Number stepSize, Number defaultValue) {
+ super(numberHolder.getValue() == null ? defaultValue : (Number) numberHolder.getValue(), minimum, maximum, stepSize);
+ this.numberHolder = numberHolder;
+ this.numberChangeListener = this.buildNumberChangeListener();
+ // postpone listening to the underlying number
+ // until we have listeners ourselves...
+ this.defaultValue = defaultValue;
+ }
+
+
+ // ********** initialization **********
+
+ protected PropertyChangeListener buildNumberChangeListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildNumberChangeListener_());
+ }
+
+ protected PropertyChangeListener buildNumberChangeListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ NumberSpinnerModelAdapter.this.synchronize(event.getNewValue());
+ }
+ @Override
+ public String toString() {
+ return "number listener";
+ }
+ };
+ }
+
+
+ // ********** SpinnerModel implementation **********
+
+ /**
+ * Extend to check whether this method is being called before we
+ * have any listeners.
+ * This is necessary because some crappy jdk code gets the value
+ * from the model *before* listening to the model. ~bjv
+ * @see javax.swing.JSpinner.DefaultEditor#DefaultEditor(javax.swing.JSpinner)
+ */
+ @Override
+ public Object getValue() {
+ if (this.getChangeListeners().length == 0) {
+ // sorry about this "lateral" call to super ~bjv
+ super.setValue(this.spinnerValueOf(this.numberHolder.getValue()));
+ }
+ return super.getValue();
+ }
+
+ /**
+ * Extend to update the underlying number directly.
+ * The resulting event will be ignored: @see #synchronizeDelegate(Object).
+ */
+ @Override
+ public void setValue(Object value) {
+ super.setValue(value);
+ this.numberHolder.setValue((Number) value);
+ }
+
+ /**
+ * Extend to start listening to the underlying number if necessary.
+ */
+ @Override
+ public void addChangeListener(ChangeListener listener) {
+ if (this.getChangeListeners().length == 0) {
+ this.numberHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.numberChangeListener);
+ this.synchronize(this.numberHolder.getValue());
+ }
+ super.addChangeListener(listener);
+ }
+
+ /**
+ * Extend to stop listening to the underlying number if appropriate.
+ */
+ @Override
+ public void removeChangeListener(ChangeListener listener) {
+ super.removeChangeListener(listener);
+ if (this.getChangeListeners().length == 0) {
+ this.numberHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.numberChangeListener);
+ }
+ }
+
+
+ // ********** queries **********
+
+ protected Number getDefaultValue() {
+ return this.defaultValue;
+ }
+
+ /**
+ * Convert to a non-null value.
+ */
+ protected Object spinnerValueOf(Object value) {
+ return (value == null) ? this.getDefaultValue() : value;
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Set the spinner value if it has changed.
+ */
+ void synchronize(Object value) {
+ Object newValue = this.spinnerValueOf(value);
+ // check to see whether the date has already been synchronized
+ // (via #setValue())
+ if ( ! this.getValue().equals(newValue)) {
+ this.setValue(newValue);
+ }
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.numberHolder);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ObjectListSelectionModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ObjectListSelectionModel.java
new file mode 100644
index 0000000..b41b388
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ObjectListSelectionModel.java
@@ -0,0 +1,437 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.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.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.iterator.IteratorTools;
+
+/**
+ * This ListSelectionModel is aware of the ListModel and
+ * provides convenience methods to access and set the
+ * selected *objects*, as opposed to the selected *indexes*.
+ */
+@SuppressWarnings("nls")
+public class ObjectListSelectionModel
+ extends DefaultListSelectionModel
+{
+ /** The list model referenced by the list selection model. */
+ private final ListModel listModel;
+
+ /** A listener that allows us to clear the selection when the list model has changed. */
+ private final ListDataListener listDataListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Construct a list selection model for the specified list model.
+ */
+ public ObjectListSelectionModel(ListModel listModel) {
+ super();
+ this.listModel = listModel;
+ this.listDataListener = this.buildListDataListener();
+ }
+
+
+ // ********** initialization **********
+
+ private ListDataListener buildListDataListener() {
+ return new ListDataListener() {
+ @Override
+ public void intervalAdded(ListDataEvent event) {
+ // this does not affect the selection
+ }
+ @Override
+ public void intervalRemoved(ListDataEvent event) {
+ // this does not affect the selection
+ }
+ @Override
+ public void contentsChanged(ListDataEvent event) {
+ ObjectListSelectionModel.this.listModelContentsChanged(event);
+ }
+ @Override
+ public String toString() {
+ return "list data listener";
+ }
+ };
+ }
+
+ /**
+ * 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
+ * single selection.
+ * A subclass can override this method if the selection
+ * should be cleared because a change could mean the selection is invalid.
+ */
+ protected void listModelContentsChanged(@SuppressWarnings("unused") ListDataEvent event) {
+ /**this.clearSelection();*/
+ }
+
+
+ // ********** ListSelectionModel implementation **********
+
+ @Override
+ public void addListSelectionListener(ListSelectionListener l) {
+ if (this.hasNoListSelectionListeners()) {
+ this.listModel.addListDataListener(this.listDataListener);
+ }
+ super.addListSelectionListener(l);
+ }
+
+ @Override
+ public void removeListSelectionListener(ListSelectionListener l) {
+ super.removeListSelectionListener(l);
+ if (this.hasNoListSelectionListeners()) {
+ this.listModel.removeListDataListener(this.listDataListener);
+ }
+ }
+
+
+ // ********** queries **********
+
+ /**
+ * Return whether this model has no listeners.
+ */
+ protected boolean hasNoListSelectionListeners() { // private-protected
+ return this.getListSelectionListeners().length == 0;
+ }
+
+ /**
+ * Return the list model referenced by the list selection model.
+ */
+ public ListModel getListModel() {
+ return this.listModel;
+ }
+
+ public int selectedValuesSize() {
+ int min = this.getMinSelectionIndex();
+ int max = this.getMaxSelectionIndex();
+
+ if ((min < 0) || (max < 0)) {
+ return 0;
+ }
+
+ int n = 0;
+ int count = this.getListModel().getSize();
+ for (int i = min; i <= max; i++) {
+ if (this.isSelectedIndex(i) && (i < count)) {
+ n++;
+ }
+ }
+ return n;
+ }
+
+ /**
+ * Return the first selected value.
+ * Return null if the selection is empty.
+ */
+ public Object selectedValue() {
+ int index = this.getMinSelectionIndex();
+ if (index == -1) {
+ return null;
+ }
+ if (this.getListModel().getSize() <= index) {
+ return null;
+ }
+ return this.getListModel().getElementAt(index);
+ }
+
+ /**
+ * Return an array of the selected values.
+ */
+ public Object[] selectedValues() {
+ int min = this.getMinSelectionIndex();
+ int max = this.getMaxSelectionIndex();
+
+ if ((min < 0) || (max < 0)) {
+ return ObjectTools.EMPTY_OBJECT_ARRAY;
+ }
+
+ int maxSize = (max - min) + 1;
+ Object[] temp = new Object[maxSize];
+ int n = 0;
+ int count = this.getListModel().getSize();
+ for (int i = min; i <= max; i++) {
+ if (this.isSelectedIndex(i) && (i < count)) {
+ temp[n++] = this.getListModel().getElementAt(i);
+ }
+ }
+ if (n == maxSize) {
+ // all the elements in the range were selected
+ return temp;
+ }
+ // only some of the elements in the range were selected
+ Object[] result = new Object[n];
+ System.arraycopy(temp, 0, result, 0, n);
+ return result;
+ }
+
+ /**
+ * Return an array of the selected indices in order.
+ */
+ 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.getListModel().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) {
+ this.setSelectedValues(IteratorTools.singletonIterator(object));
+ }
+
+ /**
+ * Set the current set of selected objects to the specified objects.
+ * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int)
+ */
+ public void setSelectedValues(Iterator<?> objects) {
+ this.setValueIsAdjusting(true);
+ this.clearSelection();
+ this.addSelectedValuesInternal(objects);
+ this.setValueIsAdjusting(false);
+ }
+
+ /**
+ * Set the current set of selected objects to the specified objects.
+ * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int)
+ */
+ 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)
+ */
+ public void setSelectedValues(Object[] objects) {
+ this.setSelectedValues(IteratorTools.iterator(objects));
+ }
+
+ /**
+ * Add the specified object to the current set of selected objects.
+ * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
+ */
+ public void addSelectedValue(Object object) {
+ this.addSelectedValues(IteratorTools.singletonIterator(object));
+ }
+
+ /**
+ * Add the specified objects to the current set of selected objects.
+ * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
+ */
+ 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) {
+ this.addSelectedValues(objects.iterator());
+ }
+
+ /**
+ * Add the specified objects to the current set of selected objects.
+ * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
+ */
+ public void addSelectedValues(Object[] objects) {
+ this.addSelectedValues(IteratorTools.iterator(objects));
+ }
+
+ /**
+ * Remove the specified object from the current set of selected objects.
+ * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
+ */
+ public void removeSelectedValue(Object object) {
+ this.removeSelectedValues(IteratorTools.singletonIterator(object));
+ }
+
+ /**
+ * Remove the specified objects from the current set of selected objects.
+ * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
+ */
+ public void removeSelectedValues(Iterator<?> objects) {
+ this.setValueIsAdjusting(true);
+ ListModel lm = this.getListModel();
+ int lmSize = lm.getSize();
+ while (objects.hasNext()) {
+ int index = this.indexOf(objects.next(), lm, lmSize);
+ this.removeSelectionInterval(index, index);
+ }
+ 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) {
+ this.removeSelectedValues(objects.iterator());
+ }
+
+ /**
+ * Remove the specified objects from the current set of selected objects.
+ * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
+ */
+ public void removeSelectedValues(Object[] objects) {
+ this.removeSelectedValues(IteratorTools.iterator(objects));
+ }
+
+ /**
+ * @see javax.swing.ListSelectionModel#getAnchorSelectionIndex()
+ * Return null if the anchor selection is empty.
+ */
+ public Object getAnchorSelectedValue() {
+ int index = this.getAnchorSelectionIndex();
+ if (index == -1) {
+ return null;
+ }
+ return this.getListModel().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.
+ */
+ public Object getLeadSelectedValue() {
+ int index = this.getLeadSelectionIndex();
+ if (index == -1) {
+ return null;
+ }
+ return this.getListModel().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.
+ */
+ public Object getMaxSelectedValue() {
+ int index = this.getMaxSelectionIndex();
+ if (index == -1) {
+ return null;
+ }
+ return this.getListModel().getElementAt(index);
+ }
+
+ /**
+ * @see javax.swing.ListSelectionModel#getMinSelectionIndex()
+ * Return null if the min selection is empty.
+ */
+ public Object getMinSelectedValue() {
+ int index = this.getMinSelectionIndex();
+ if (index == -1) {
+ return null;
+ }
+ return this.getListModel().getElementAt(index);
+ }
+
+ /**
+ * @see javax.swing.ListSelectionModel#isSelectedIndex(int)
+ */
+ public boolean valueIsSelected(Object object) {
+ return this.isSelectedIndex(this.indexOf(object));
+ }
+
+ /**
+ * 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();
+ int listModelSize = lm.getSize();
+ while (objects.hasNext()) {
+ int index = this.indexOf(objects.next(), lm, listModelSize);
+ this.addSelectionInterval(index, index);
+ }
+ }
+
+ /**
+ * Return the index in the list model of the specified object.
+ * Return -1 if the object is not in the list model.
+ */
+ private int indexOf(Object object) {
+ ListModel lm = this.getListModel();
+ return this.indexOf(object, lm, lm.getSize());
+ }
+
+ /**
+ * Return the index in the list model of the specified object.
+ * Return -1 if the object is not in the list model.
+ */
+ // we're just jerking around with performance optimizations here
+ // (in memory of Phil...);
+ // call this method inside loops that do not modify the listModel
+ private int indexOf(Object object, ListModel lm, int listModelSize) {
+ for (int i = listModelSize; i-- > 0; ) {
+ if (lm.getElementAt(i).equals(object)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/PrimitiveListTreeModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/PrimitiveListTreeModel.java
new file mode 100644
index 0000000..6ec072d
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/PrimitiveListTreeModel.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTListChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+
+/**
+ * This TreeModel implementation provides a tree with a "null" root that
+ * has a set of "primitive" children. These "primitive" children do not have
+ * children themselves, making the tree a maximum of 2 levels deep.
+ * This model automatically synchronizes the root's children with a
+ * ListValueModel that holds a collection of primitive (non-model) objects
+ * (e.g. Strings).
+ *
+ * This is useful for providing an "editable" list of primitives. Since the JDK
+ * does not provide us with an editable listbox, we must use an editable tree.
+ * We wrap everything in DefaultMutableTreeNodes.
+ *
+ * Subclasses must implement #primitiveChanged(int, Object) and update
+ * the model appropriately. This method is called when the user edits the
+ * list directly and presses <Enter>.
+ *
+ * The JTree using this model must be configured as "editable":
+ * tree.setEditable(true);
+ */
+// TODO convert to use an adapter instead of requiring subclass
+public abstract class PrimitiveListTreeModel
+ extends DefaultTreeModel
+{
+ /** a model on the list of primitives */
+ private final ListValueModel<?> listHolder;
+
+ /** a listener that handles the adding, removing, and replacing of the primitives */
+ private final ListChangeListener listChangeListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Public constructor - the list holder is required
+ */
+ public PrimitiveListTreeModel(ListValueModel<?> listHolder) {
+ super(new DefaultMutableTreeNode(null, true)); // true = the root can have children
+ if (listHolder == null) {
+ throw new NullPointerException();
+ }
+ this.listHolder = listHolder;
+ this.listChangeListener = this.buildListChangeListener();
+ // postpone listening to the model until we have listeners ourselves
+ }
+
+ protected ListChangeListener buildListChangeListener() {
+ return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
+ }
+
+ protected ListChangeListener buildListChangeListener_() {
+ return new PrimitiveListChangeListener();
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Subclasses should override this method to update the
+ * model appropriately. The primitive at the specified index was
+ * edited directly by the user and the new value is as specified.
+ * Convert the value appropriately and place it in the model.
+ */
+ protected abstract void primitiveChanged(int index, Object newValue);
+
+
+ // ********** TreeModel implementation **********
+
+ /**
+ * Override to change the underlying model instead of changing the node directly.
+ */
+ @Override
+ public void valueForPathChanged(TreePath path, Object newValue) {
+ TreeNode node = (TreeNode) path.getLastPathComponent();
+ int index = ((TreeNode) this.getRoot()).getIndex(node);
+ this.primitiveChanged(index, newValue);
+ }
+
+ /**
+ * Extend to start listening to the underlying model if necessary.
+ */
+ @Override
+ public void addTreeModelListener(TreeModelListener l) {
+ if (this.getTreeModelListeners().length == 0) {
+ this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+ this.synchronizeList();
+ }
+ super.addTreeModelListener(l);
+ }
+
+ /**
+ * Extend to stop listening to the underlying model if appropriate.
+ */
+ @Override
+ public void removeTreeModelListener(TreeModelListener l) {
+ super.removeTreeModelListener(l);
+ if (this.getTreeModelListeners().length == 0) {
+ this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+ }
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Synchronize our list of nodes with the list of primitives
+ */
+ void synchronizeList() {
+ this.clearList();
+ this.buildList();
+ }
+
+ void clearList() {
+ int childcount = this.root.getChildCount();
+ for (int i = childcount - 1; i >= 0; i--) {
+ this.removeNodeFromParent((MutableTreeNode)this.root.getChildAt(i));
+ }
+ }
+
+ private void buildList() {
+ for (Iterator<?> stream = this.listHolder.iterator(); stream.hasNext(); ) {
+ this.addPrimitive(stream.next());
+ }
+ }
+
+ /**
+ * Add the specified primitive to the end of the list.
+ */
+ private void addPrimitive(Object primitive) {
+ this.insertPrimitive(this.root.getChildCount(), primitive);
+ }
+
+ /**
+ * Create a node for the specified primitive
+ * and insert it as a child of the root.
+ */
+ void insertPrimitive(int index, Object primitive) {
+ DefaultMutableTreeNode node = new DefaultMutableTreeNode(primitive, false); // don't allow children on the child node
+ this.insertNodeInto(node, (MutableTreeNode) this.root, index);
+ }
+
+ /**
+ * Remove node at the specified index.
+ */
+ MutableTreeNode removeNode(int index) {
+ MutableTreeNode node = (MutableTreeNode) this.root.getChildAt(index);
+ this.removeNodeFromParent(node);
+ return node;
+ }
+
+ /**
+ * Replace the user object of the node at childIndex.
+ */
+ void replacePrimitive(int index, Object primitive) {
+ MutableTreeNode node = (MutableTreeNode) this.root.getChildAt(index);
+ node.setUserObject(primitive);
+ this.nodeChanged(node);
+ }
+
+
+ // ********** inner class **********
+
+ private class PrimitiveListChangeListener implements ListChangeListener {
+ PrimitiveListChangeListener() {
+ super();
+ }
+
+ @Override
+ public void itemsAdded(ListAddEvent event) {
+ int i = event.getIndex();
+ for (Object item : event.getItems()) {
+ PrimitiveListTreeModel.this.insertPrimitive(i++, item);
+ }
+ }
+
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {
+ for (int i = 0; i < event.getItemsSize(); i++) {
+ PrimitiveListTreeModel.this.removeNode(event.getIndex());
+ }
+ }
+
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {
+ int i = event.getIndex();
+ for (Object item : event.getNewItems()) {
+ PrimitiveListTreeModel.this.replacePrimitive(i++, item);
+ }
+ }
+
+ @Override
+ public void itemsMoved(ListMoveEvent event) {
+ ArrayList<MutableTreeNode> temp = new ArrayList<MutableTreeNode>(event.getLength());
+ for (int i = 0; i < event.getLength(); i++) {
+ temp.add(PrimitiveListTreeModel.this.removeNode(event.getSourceIndex()));
+ }
+ int i = event.getTargetIndex();
+ for (MutableTreeNode node : temp) {
+ PrimitiveListTreeModel.this.insertPrimitive(i++, node);
+ }
+ }
+
+ @Override
+ public void listCleared(ListClearEvent event) {
+ PrimitiveListTreeModel.this.clearList();
+ }
+
+ @Override
+ public void listChanged(ListChangeEvent event) {
+ PrimitiveListTreeModel.this.synchronizeList();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/RadioButtonModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/RadioButtonModelAdapter.java
new file mode 100644
index 0000000..9ca700c
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/RadioButtonModelAdapter.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import org.eclipse.persistence.tools.utility.filter.Filter;
+import org.eclipse.persistence.tools.utility.model.value.FilteringModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TransformationModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.transformer.Transformer;
+
+/**
+ * This {@link javax.swing.ButtonModel} can be used to keep a listener
+ * (e.g. a {@link javax.swing.JRadioButton}) in synch with a (typically shared)
+ * {@link org.eclipse.jpt.common.utility.model.value.PropertyValueModel}
+ * that holds one value out of a set of values.
+ * <p>
+ * <strong>NB:</strong> Do <em>not</em> use this model with a
+ * {@link javax.swing.ButtonGroup}, since the
+ * shared value holder and the wrappers built by this adapter will
+ * keep the appropriate radio button checked. Also, this allows
+ * us to uncheck all the radio buttons in a group when the shared
+ * value is <code>null</code>.
+ */
+public class RadioButtonModelAdapter
+ extends ToggleButtonModelAdapter
+{
+ private static final long serialVersionUID = 1L;
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the value holder is required.
+ */
+ public RadioButtonModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue, boolean defaultValue) {
+ super(buildBooleanHolder(valueHolder, buttonValue), defaultValue);
+ }
+
+ /**
+ * Constructor - the value holder is required.
+ * The default value will be false.
+ */
+ public RadioButtonModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue) {
+ super(buildBooleanHolder(valueHolder, buttonValue));
+ }
+
+
+ // ********** static methods **********
+
+ /**
+ * Build up a set of wrappers that will convert the
+ * specified value holder and button value to/from a boolean.
+ *
+ * If the value holder's value matches the button value,
+ * the wrapper will return true. Likewise, if the value holder's
+ * value is set to true, the wrapper will set the value holder's
+ * value to the button value.
+ */
+ public static ModifiablePropertyValueModel<Boolean> buildBooleanHolder(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue) {
+ ModifiablePropertyValueModel<Object> filteringPVM = new FilteringModifiablePropertyValueModel<Object>(valueHolder, Filter.Transparent.instance(), new SetRadioButtonFilter(buttonValue));
+ return new TransformationModifiablePropertyValueModel<Object, Boolean>(filteringPVM, new RadioButtonTransformer(buttonValue), new ReverseRadioButtonTransformer(buttonValue));
+ }
+
+
+ // ********** overrides **********
+
+ /**
+ * The user cannot de-select a radio button - the user
+ * can only *select* a radio button. Only the model can
+ * cause a radio button to be de-selected. We use the
+ * ARMED flag to indicate whether we are being de-selected
+ * by the user.
+ */
+ @Override
+ public void setSelected(boolean b) {
+ // do not allow the user to de-select a radio button
+ // radio buttons can
+ if ((b == false) && this.isArmed()) {
+ return;
+ }
+ super.setSelected(b);
+ }
+
+
+ // ********** filters **********
+
+ /**
+ * This filter will only pass through a new value to the wrapped
+ * value model when it matches the configured button value.
+ */
+ public static class SetRadioButtonFilter
+ implements Filter<Object>
+ {
+ private Object buttonValue;
+
+ public SetRadioButtonFilter(Object buttonValue) {
+ super();
+ this.buttonValue = buttonValue;
+ }
+
+ /**
+ * pass through the value to the wrapped property value model
+ * *only* when it matches our button value
+ */
+ @Override
+ public boolean accept(Object value) {
+ return (value != null) && value.equals(this.buttonValue);
+ }
+ }
+
+
+ // ********** transformers **********
+
+ /**
+ * This transformer will convert a value to {@link Boolean#TRUE}
+ * when it matches the configured button value.
+ */
+ public static class RadioButtonTransformer
+ implements Transformer<Object, Boolean>
+ {
+ private Object buttonValue;
+
+ public RadioButtonTransformer(Object buttonValue) {
+ super();
+ this.buttonValue = buttonValue;
+ }
+
+ /**
+ * If the specified value matches the button value return {@link Boolean#TRUE},
+ * if it is some other value return {@link Boolean#FALSE};
+ * but if it is <code>null</code> simply pass it through because it will
+ * cause the button model's default value to be used
+ */
+ @Override
+ public Boolean transform(Object value) {
+ return (value == null) ? null : Boolean.valueOf(value.equals(this.buttonValue));
+ }
+ }
+
+ /**
+ * This transformer will convert {@link Boolean#TRUE} to the configured
+ * button value and {@link Boolean#FALSE} to <code>null</code>.
+ */
+ public static class ReverseRadioButtonTransformer
+ implements Transformer<Boolean, Object>
+ {
+ private Object buttonValue;
+
+ public ReverseRadioButtonTransformer(Object buttonValue) {
+ super();
+ this.buttonValue = buttonValue;
+ }
+
+ /**
+ * If the specified value is {@link Boolean#TRUE},
+ * pass through the our button value;
+ * otherwise pass through <code>null</code>.
+ */
+ @Override
+ public Object transform (Boolean value) {
+ return (value.booleanValue()) ? this.buttonValue : null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/SpinnerModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/SpinnerModelAdapter.java
new file mode 100644
index 0000000..180f629
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/SpinnerModelAdapter.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import javax.swing.AbstractSpinnerModel;
+import javax.swing.SpinnerModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.SpinnerModel can be used to keep a ChangeListener
+ * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a value.
+ *
+ * Note: it is likely you want to use one of the following classes instead of
+ * this one:
+ * DateSpinnerModelAdapter
+ * NumberSpinnerModelAdapter
+ * ListSpinnerModelAdapter
+ *
+ * NB: This model should only be used for values that have a fairly
+ * inexpensive #equals() implementation.
+ * @see #synchronizeDelegate(Object)
+ */
+@SuppressWarnings("nls")
+public class SpinnerModelAdapter
+ extends AbstractSpinnerModel
+{
+ /** The delegate spinner model whose behavior we "enhance". */
+ protected final SpinnerModel delegate;
+
+ /** A listener that allows us to forward any changes made to the delegate spinner model. */
+ protected final ChangeListener delegateListener;
+
+ /** A value model on the underlying value. */
+ protected final ModifiablePropertyValueModel<Object> valueHolder;
+
+ /** A listener that allows us to synchronize with changes made to the underlying value. */
+ protected final PropertyChangeListener valueListener;
+
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the value holder and delegate are required.
+ */
+ public SpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, SpinnerModel delegate) {
+ super();
+ if (valueHolder == null || delegate == null) {
+ throw new NullPointerException();
+ }
+ this.valueHolder = valueHolder;
+ this.delegate = delegate;
+ // postpone listening to the underlying value
+ // until we have listeners ourselves...
+ this.valueListener = this.buildValueListener();
+ this.delegateListener = this.buildDelegateListener();
+ }
+
+ /**
+ * Constructor - the value holder is required.
+ * This will wrap a simple number spinner model.
+ */
+ public SpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder) {
+ this(valueHolder, new SpinnerNumberModel());
+ }
+
+
+ // ********** initialization **********
+
+ protected PropertyChangeListener buildValueListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildValueListener_());
+ }
+
+ protected PropertyChangeListener buildValueListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ SpinnerModelAdapter.this.valueChanged(event);
+ }
+ @Override
+ public String toString() {
+ return "value listener";
+ }
+ };
+ }
+
+ /**
+ * expand access a bit for inner class
+ */
+ @Override
+ protected void fireStateChanged() {
+ super.fireStateChanged();
+ }
+
+ protected ChangeListener buildDelegateListener() {
+ return new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent event) {
+ // forward the event, with this as the source
+ SpinnerModelAdapter.this.fireStateChanged();
+ }
+ @Override
+ public String toString() {
+ return "delegate listener";
+ }
+ };
+ }
+
+
+ // ********** SpinnerModel implementation **********
+
+ @Override
+ public Object getValue() {
+ return this.delegate.getValue();
+ }
+
+ /**
+ * Extend to update the underlying value directly.
+ * The resulting event will be ignored: @see #synchronizeDelegate(Object).
+ */
+ @Override
+ public void setValue(Object value) {
+ this.delegate.setValue(value);
+ this.valueHolder.setValue(value);
+ }
+
+ @Override
+ public Object getNextValue() {
+ return this.delegate.getNextValue();
+ }
+
+ @Override
+ public Object getPreviousValue() {
+ return this.delegate.getPreviousValue();
+ }
+
+ /**
+ * Extend to start listening to the underlying value if necessary.
+ */
+ @Override
+ public void addChangeListener(ChangeListener listener) {
+ if (this.listenerList.getListenerCount(ChangeListener.class) == 0) {
+ this.delegate.addChangeListener(this.delegateListener);
+ this.engageValueHolder();
+ }
+ super.addChangeListener(listener);
+ }
+
+ /**
+ * Extend to stop listening to the underlying value if appropriate.
+ */
+ @Override
+ public void removeChangeListener(ChangeListener listener) {
+ super.removeChangeListener(listener);
+ if (this.listenerList.getListenerCount(ChangeListener.class) == 0) {
+ this.disengageValueHolder();
+ this.delegate.removeChangeListener(this.delegateListener);
+ }
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * A third party has modified the underlying value.
+ * Synchronize the delegate model accordingly.
+ */
+ protected void valueChanged(PropertyChangeEvent event) {
+ this.synchronizeDelegate(event.getNewValue());
+ }
+
+ /**
+ * Set the delegate's value if it has changed.
+ */
+ protected void synchronizeDelegate(Object value) {
+ // check to see whether the delegate has already been synchronized
+ // (via #setValue())
+ if ( ! this.delegate.getValue().equals(value)) {
+ this.delegate.setValue(value);
+ }
+ }
+
+ protected void engageValueHolder() {
+ this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueListener);
+ this.synchronizeDelegate(this.valueHolder.getValue());
+ }
+
+ protected void disengageValueHolder() {
+ this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueListener);
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.valueHolder);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TableModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TableModelAdapter.java
new file mode 100644
index 0000000..171289f
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TableModelAdapter.java
@@ -0,0 +1,470 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTListChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.CollectionListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This TableModel can be used to keep a TableModelListener (e.g. a JTable)
+ * in synch with a ListValueModel that holds a collection of model objects,
+ * each of which corresponds to a row in the table.
+ * Typically, each column of the table will be bound to a different aspect
+ * of the contained model objects.
+ *
+ * For example, a MWTable has an attribute 'databaseFields' that holds
+ * a collection of MWDatabaseFields that would correspond to the rows of
+ * a JTable; and each MWDatabaseField has a number
+ * of attributes (e.g. name, type, size) that can be bound to the columns of
+ * a row in the JTable. As these database fields are added, removed, and
+ * changed, this model will keep the listeners aware of the changes.
+ *
+ * An instance of this TableModel must be supplied with a
+ * list holder (e.g. the 'databaseFields'), which is a value
+ * model on the bound collection This is required - the
+ * collection itself can be null, but the list value model that
+ * holds it is required. Typically this list will be sorted (@see
+ * SortedListValueModelAdapter).
+ *
+ * This TableModel must also be supplied with a ColumnAdapter that
+ * will be used to configure the headers, renderers, editors, and contents
+ * of the various columns.
+ *
+ * Design decision:
+ * Cell listener options (from low space/high time to high space/low time):
+ * - 1 cell listener listening to every cell (this is the current implementation)
+ * - 1 cell listener per row
+ * - 1 cell listener per cell
+ */
+@SuppressWarnings("nls")
+public class TableModelAdapter<E>
+ extends AbstractTableModel
+{
+ /**
+ * a list of user objects that are converted to
+ * rows via the column adapter
+ */
+ 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<ModifiablePropertyValueModel<Object>[]> rows;
+
+ /**
+ * client-supplied adapter that provides with the various column
+ * settings and converts the objects in the LVM
+ * into an array of cell models
+ */
+ private final ColumnAdapter columnAdapter;
+
+ /**
+ * the single listener that listens to every cell's model
+ */
+ private final PropertyChangeListener cellListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Construct a table model adapter for the specified objects
+ * and adapter.
+ */
+ public TableModelAdapter(ListValueModel<? extends E> listHolder, ColumnAdapter columnAdapter) {
+ super();
+ if (listHolder == null) {
+ throw new NullPointerException();
+ }
+ this.listHolder = listHolder;
+ this.columnAdapter = columnAdapter;
+ this.listChangeListener = this.buildListChangeListener();
+ this.rows = new ArrayList<ModifiablePropertyValueModel<Object>[]>();
+ this.cellListener = this.buildCellListener();
+ }
+
+ /**
+ * Construct a table model adapter for the specified objects
+ * and adapter.
+ */
+ public TableModelAdapter(CollectionValueModel<? extends E> collectionHolder, ColumnAdapter columnAdapter) {
+ this(new CollectionListValueModelAdapter<E>(collectionHolder), columnAdapter);
+ }
+
+
+ // ********** initialization **********
+
+ protected ListChangeListener buildListChangeListener() {
+ return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
+ }
+
+ protected ListChangeListener buildListChangeListener_() {
+ return new ListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) {
+ TableModelAdapter.this.addRows(event.getIndex(), event.getItemsSize(), this.getItems(event));
+ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {
+ TableModelAdapter.this.removeRows(event.getIndex(), event.getItemsSize());
+ }
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {
+ TableModelAdapter.this.replaceRows(event.getIndex(), this.getNewItems(event));
+ }
+ @Override
+ public void itemsMoved(ListMoveEvent event) {
+ TableModelAdapter.this.moveRows(event.getTargetIndex(), event.getSourceIndex(), event.getLength());
+ }
+ @Override
+ public void listCleared(ListClearEvent event) {
+ TableModelAdapter.this.clearTable();
+ }
+ @Override
+ public void listChanged(ListChangeEvent event) {
+ TableModelAdapter.this.rebuildTable();
+ }
+ // minimized scope of suppressed warnings
+ @SuppressWarnings("unchecked")
+ protected Iterable<Object> getItems(ListAddEvent event) {
+ return (Iterable<Object>) event.getItems();
+ }
+ // minimized scope of suppressed warnings
+ @SuppressWarnings("unchecked")
+ protected Iterable<Object> getNewItems(ListReplaceEvent event) {
+ return (Iterable<Object>) event.getNewItems();
+ }
+ @Override
+ public String toString() {
+ return "list listener";
+ }
+ };
+ }
+
+
+ protected PropertyChangeListener buildCellListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildCellListener_());
+ }
+
+ protected PropertyChangeListener buildCellListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public void propertyChanged(PropertyChangeEvent event) {
+ TableModelAdapter.this.cellChanged((ModifiablePropertyValueModel<Object>) event.getSource());
+ }
+ @Override
+ public String toString() {
+ return "cell listener";
+ }
+ };
+ }
+
+
+ // ********** TableModel implementation **********
+
+ @Override
+ public int getColumnCount() {
+ return this.columnAdapter.columnCount();
+ }
+
+ @Override
+ public int getRowCount() {
+ return this.rows.size();
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ return this.columnAdapter.columnName(column);
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ return this.columnAdapter.columnClass(columnIndex);
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ return this.columnAdapter.columnIsEditable(columnIndex);
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ ModifiablePropertyValueModel<Object>[] row = this.rows.get(rowIndex);
+ return row[columnIndex].getValue();
+ }
+
+ @Override
+ public void setValueAt(Object value, int rowIndex, int columnIndex) {
+ ModifiablePropertyValueModel<Object>[] row = this.rows.get(rowIndex);
+ row[columnIndex].setValue(value);
+ }
+
+ /**
+ * Extend to start listening to the underlying model if necessary.
+ */
+ @Override
+ public void addTableModelListener(TableModelListener l) {
+ if (this.hasNoTableModelListeners()) {
+ this.engageModel();
+ }
+ super.addTableModelListener(l);
+ }
+
+ /**
+ * Extend to stop listening to the underlying model if necessary.
+ */
+ @Override
+ public void removeTableModelListener(TableModelListener l) {
+ super.removeTableModelListener(l);
+ if (this.hasNoTableModelListeners()) {
+ this.disengageModel();
+ }
+ }
+
+
+ // ********** public API **********
+
+ /**
+ * Return the underlying list model.
+ */
+ public ListValueModel<? extends E> getModel() {
+ return this.listHolder;
+ }
+
+ /**
+ * Set the underlying list model.
+ */
+ public void setModel(ListValueModel<E> listHolder) {
+ if (listHolder == null) {
+ throw new NullPointerException();
+ }
+ boolean hasListeners = this.hasTableModelListeners();
+ if (hasListeners) {
+ this.disengageModel();
+ }
+ this.listHolder = listHolder;
+ if (hasListeners) {
+ this.engageModel();
+ this.fireTableDataChanged();
+ }
+ }
+
+ /**
+ * Set the underlying collection model.
+ */
+ public void setModel(CollectionValueModel<E> collectionHolder) {
+ this.setModel(new CollectionListValueModelAdapter<E>(collectionHolder));
+ }
+
+
+ // ********** queries **********
+
+ /**
+ * Return whether this model has no listeners.
+ */
+ protected boolean hasNoTableModelListeners() {
+ return this.listenerList.getListenerCount(TableModelListener.class) == 0;
+ }
+
+ /**
+ * Return whether this model has any listeners.
+ */
+ protected boolean hasTableModelListeners() {
+ return ! this.hasNoTableModelListeners();
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Start listening to the list of objects and the various aspects
+ * of the objects that make up the rows.
+ */
+ private void engageModel() {
+ this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+ this.engageAllCells();
+ }
+
+ /**
+ * Convert the objects into rows and listen to the cells.
+ */
+ private void engageAllCells() {
+ this.rows.ensureCapacity(this.listHolder.size());
+ for (Iterator<? extends E> stream = this.listHolder.iterator(); stream.hasNext(); ) {
+ ModifiablePropertyValueModel<Object>[] row = this.columnAdapter.cellModels(stream.next());
+ this.engageRow(row);
+ this.rows.add(row);
+ }
+ }
+
+ /**
+ * Listen to the cells in the specified row.
+ */
+ private void engageRow(ModifiablePropertyValueModel<Object>[] row) {
+ for (int i = row.length; i-- > 0; ) {
+ row[i].addPropertyChangeListener(PropertyValueModel.VALUE, this.cellListener);
+ }
+ }
+
+ /**
+ * Stop listening.
+ */
+ private void disengageModel() {
+ this.disengageAllCells();
+ this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+ }
+
+ private void disengageAllCells() {
+ for (ModifiablePropertyValueModel<Object>[] row : this.rows) {
+ this.disengageRow(row);
+ }
+ this.rows.clear();
+ }
+
+ private void disengageRow(ModifiablePropertyValueModel<Object>[] row) {
+ for (int i = row.length; i-- > 0; ) {
+ row[i].removePropertyChangeListener(PropertyValueModel.VALUE, this.cellListener);
+ }
+ }
+
+ /**
+ * brute-force search for the cell(s) that changed...
+ */
+ void cellChanged(ModifiablePropertyValueModel<Object> cellHolder) {
+ for (int i = this.rows.size(); i-- > 0; ) {
+ ModifiablePropertyValueModel<Object>[] row = this.rows.get(i);
+ for (int j = row.length; j-- > 0; ) {
+ if (row[j] == cellHolder) {
+ this.fireTableCellUpdated(i, j);
+ }
+ }
+ }
+ }
+
+ /**
+ * convert the items to rows
+ */
+ void addRows(int index, int size, Iterable<Object> items) {
+ List<ModifiablePropertyValueModel<Object>[]> newRows = new ArrayList<ModifiablePropertyValueModel<Object>[]>(size);
+ for (Object item : items) {
+ ModifiablePropertyValueModel<Object>[] row = this.columnAdapter.cellModels(item);
+ this.engageRow(row);
+ newRows.add(row);
+ }
+ this.rows.addAll(index, newRows);
+ this.fireTableRowsInserted(index, index + size - 1);
+ }
+
+ void removeRows(int index, int size) {
+ for (int i = 0; i < size; i++) {
+ this.disengageRow(this.rows.remove(index));
+ }
+ this.fireTableRowsDeleted(index, index + size - 1);
+ }
+
+ void replaceRows(int index, Iterable<Object> items) {
+ int i = index;
+ for (Object item : items) {
+ ModifiablePropertyValueModel<Object>[] row = this.rows.get(i);
+ this.disengageRow(row);
+ row = this.columnAdapter.cellModels(item);
+ this.engageRow(row);
+ this.rows.set(i, row);
+ i++;
+ }
+ this.fireTableRowsUpdated(index, i - 1);
+ }
+
+ void moveRows(int targetIndex, int sourceIndex, int length) {
+ ArrayList<ModifiablePropertyValueModel<Object>[]> temp = new ArrayList<ModifiablePropertyValueModel<Object>[]>(length);
+ for (int i = 0; i < length; i++) {
+ temp.add(this.rows.remove(sourceIndex));
+ }
+ this.rows.addAll(targetIndex, temp);
+
+ int start = Math.min(targetIndex, sourceIndex);
+ int end = Math.max(targetIndex, sourceIndex) + length - 1;
+ this.fireTableRowsUpdated(start, end);
+ }
+
+ void clearTable() {
+ this.disengageAllCells();
+ this.fireTableDataChanged();
+ }
+
+ void rebuildTable() {
+ this.disengageAllCells();
+ this.engageAllCells();
+ this.fireTableDataChanged();
+ }
+
+
+ /**
+ * This adapter is used by the table model adapter to
+ * convert a model object into the models used for each of
+ * the cells for the object's corresponding row in the table.
+ */
+ public interface ColumnAdapter {
+ /**
+ * Return the number of columns in the table.
+ * Typically this is static.
+ */
+ int columnCount();
+
+ /**
+ * Return the name of the specified column.
+ */
+ String columnName(int index);
+
+ /**
+ * Return the class of the specified column.
+ */
+ Class<?> columnClass(int index);
+
+ /**
+ * Return whether the specified column is editable.
+ * Typically this is the same for every row.
+ */
+ boolean columnIsEditable(int index);
+
+ /**
+ * Return the cell models for the specified subject
+ * that corresponds to a single row in the table.
+ */
+ ModifiablePropertyValueModel<Object>[] cellModels(Object subject);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ToggleButtonModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ToggleButtonModelAdapter.java
new file mode 100644
index 0000000..bf22de0
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ToggleButtonModelAdapter.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.awt.event.ActionListener;
+import java.awt.event.ItemListener;
+import javax.swing.JToggleButton.ToggleButtonModel;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.ButtonModel can be used to keep a listener
+ * (e.g. a JCheckBox or a JRadioButton) in synch with a PropertyValueModel
+ * on a boolean.
+ */
+@SuppressWarnings("nls")
+public class ToggleButtonModelAdapter
+ extends ToggleButtonModel
+{
+ /**
+ * The default setting for the toggle button; for when the underlying model is null.
+ * The default [default value] is false (i.e. the toggle button is unchecked/empty).
+ */
+ protected final boolean defaultValue;
+
+ /** A value model on the underlying model boolean. */
+ protected final ModifiablePropertyValueModel<Boolean> booleanHolder;
+
+ /**
+ * A listener that allows us to synchronize with
+ * changes made to the underlying model boolean.
+ */
+ protected final PropertyChangeListener booleanChangeListener;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Constructor - the boolean holder is required.
+ */
+ public ToggleButtonModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder, boolean defaultValue) {
+ super();
+ if (booleanHolder == null) {
+ throw new NullPointerException();
+ }
+ this.booleanHolder = booleanHolder;
+ this.booleanChangeListener = this.buildBooleanChangeListener();
+ // postpone listening to the underlying model
+ // until we have listeners ourselves...
+ this.defaultValue = defaultValue;
+ }
+
+ /**
+ * Constructor - the boolean holder is required.
+ * The default value will be false.
+ */
+ public ToggleButtonModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder) {
+ this(booleanHolder, false);
+ }
+
+
+ // ********** initialization **********
+
+ protected PropertyChangeListener buildBooleanChangeListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildBooleanChangeListener_());
+ }
+
+ protected PropertyChangeListener buildBooleanChangeListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ ToggleButtonModelAdapter.this.booleanChanged(event);
+ }
+ @Override
+ public String toString() {
+ return "boolean listener";
+ }
+ };
+ }
+
+
+ // ********** ButtonModel implementation **********
+
+ /**
+ * Extend to update the underlying model if necessary.
+ */
+ @Override
+ public void setSelected(boolean b) {
+ if (this.isSelected() != b) { // stop the recursion!
+ super.setSelected(b);//put the super call first, otherwise the following gets called twice
+ this.booleanHolder.setValue(Boolean.valueOf(b));
+ }
+ }
+
+ /**
+ * Extend to start listening to the underlying model if necessary.
+ */
+ @Override
+ public void addActionListener(ActionListener l) {
+ if (this.hasNoListeners()) {
+ this.engageModel();
+ }
+ super.addActionListener(l);
+ }
+
+ /**
+ * Extend to stop listening to the underlying model if appropriate.
+ */
+ @Override
+ public void removeActionListener(ActionListener l) {
+ super.removeActionListener(l);
+ if (this.hasNoListeners()) {
+ this.disengageModel();
+ }
+ }
+
+ /**
+ * Extend to start listening to the underlying model if necessary.
+ */
+ @Override
+ public void addItemListener(ItemListener l) {
+ if (this.hasNoListeners()) {
+ this.engageModel();
+ }
+ super.addItemListener(l);
+ }
+
+ /**
+ * Extend to stop listening to the underlying model if appropriate.
+ */
+ @Override
+ public void removeItemListener(ItemListener l) {
+ super.removeItemListener(l);
+ if (this.hasNoListeners()) {
+ this.disengageModel();
+ }
+ }
+
+ /**
+ * Extend to start listening to the underlying model if necessary.
+ */
+ @Override
+ public void addChangeListener(ChangeListener l) {
+ if (this.hasNoListeners()) {
+ this.engageModel();
+ }
+ super.addChangeListener(l);
+ }
+
+ /**
+ * Extend to stop listening to the underlying model if appropriate.
+ */
+ @Override
+ public void removeChangeListener(ChangeListener l) {
+ super.removeChangeListener(l);
+ if (this.hasNoListeners()) {
+ this.disengageModel();
+ }
+ }
+
+
+ // ********** queries **********
+
+ /**
+ * Return whether we have no listeners at all.
+ */
+ protected boolean hasNoListeners() {
+ return this.listenerList.getListenerCount() == 0;
+ }
+
+ protected boolean getDefaultValue() {
+ return this.defaultValue;
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Synchronize with the specified value.
+ * If it is null, use the default value (which is typically false).
+ */
+ protected void setSelected(Boolean value) {
+ if (value == null) {
+ this.setSelected(this.getDefaultValue());
+ } else {
+ this.setSelected(value.booleanValue());
+ }
+ }
+
+ /**
+ * The underlying model has changed - synchronize accordingly.
+ */
+ protected void booleanChanged(PropertyChangeEvent event) {
+ this.setSelected((Boolean) event.getNewValue());
+ }
+
+ protected void engageModel() {
+ this.booleanHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener);
+ this.setSelected(this.booleanHolder.getValue());
+ }
+
+ protected void disengageModel() {
+ this.booleanHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener);
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.booleanHolder);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TreeModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TreeModelAdapter.java
new file mode 100644
index 0000000..f65bde0
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TreeModelAdapter.java
@@ -0,0 +1,934 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreePath;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.StateChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.StateChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTListChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTStateChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.StaticPropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TreeNodeValueModel;
+
+/**
+ * This javax.swing.tree.TreeModel can be used to keep a TreeModelListener
+ * (e.g. a JTree) in synch with a tree of TreeNodeValueModel objects. Unlike
+ * javax.swing.tree.DefaultTreeModel, you do not add and remove nodes with
+ * methods implemented here. You can add and remove nodes by adding and
+ * removing them directly to/from the nodes (or, more typically, the domain
+ * objects the nodes are wrapping and listening to).
+ *
+ * Due to limitations in JTree, the root of the tree can never be null,
+ * which, typically, should not be a problem. (If you want to display an empty
+ * tree you can set the JTree's treeModel to null.)
+ */
+@SuppressWarnings("nls")
+public class TreeModelAdapter<T>
+ extends AbstractTreeModel
+{
+ /**
+ * A value model on the underlying tree's root node and its
+ * corresponding listener. This allows clients to swap out
+ * the entire tree. Due to limitations in JTree, the root should
+ * never be set to null while we have listeners.
+ */
+ private final PropertyValueModel<TreeNodeValueModel<T>> rootHolder;
+ private final PropertyChangeListener rootListener;
+
+ /**
+ * A listener that notifies us when a node's internal
+ * "state" changes (as opposed to the node's value or list of
+ * children), allowing us to forward notification to our listeners.
+ */
+ private final StateChangeListener nodeStateListener;
+
+ /**
+ * A listener that notifies us when a node's "value"
+ * changes (as opposed to the node's state or list of
+ * children), allowing us to forward notification to our listeners.
+ * Typically, this will only happen with nodes that hold
+ * primitive data.
+ */
+ private final PropertyChangeListener nodeValueListener;
+
+ /**
+ * A listener that notifies us when an underlying node's
+ * "list" of children changes, allowing us to keep our
+ * internal tree in synch with the underlying tree model.
+ */
+ private final ListChangeListener childrenListener;
+
+ /* these attributes make up our internal tree */
+ /**
+ * The root cannot be null while we have listeners, which is
+ * most of the time. The root is cached so we can disengage
+ * from it when it has been swapped out.
+ */
+ private TreeNodeValueModel<T> root;
+
+ /**
+ * Map the nodes to their lists of children.
+ * We cache these so we can swap out the entire list of children
+ * when we receive a #listChanged() event (which does not include
+ * the items that were affected).
+ * @see ChangeEventChangePolicy#rebuildChildren()
+ */
+ final IdentityHashMap<TreeNodeValueModel<T>, List<TreeNodeValueModel<T>>> childrenLists;
+
+ /**
+ * Map the children models to their parents.
+ * We cache these so we can figure out the "real" source of the
+ * list change events (the parent).
+ * @see EventChangePolicy#parent()
+ */
+ final IdentityHashMap<ListValueModel<TreeNodeValueModel<T>>, TreeNodeValueModel<T>> parents;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Construct a tree model for the specified root.
+ */
+ public TreeModelAdapter(PropertyValueModel<TreeNodeValueModel<T>> rootHolder) {
+ super();
+ if (rootHolder == null) {
+ throw new NullPointerException();
+ }
+ this.rootHolder = rootHolder;
+ this.rootListener = this.buildRootListener();
+ this.nodeStateListener = this.buildNodeStateListener();
+ this.nodeValueListener = this.buildNodeValueListener();
+ this.childrenListener = this.buildChildrenListener();
+ 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<T> root) {
+ this(new StaticPropertyValueModel<TreeNodeValueModel<T>>(root));
+ }
+
+
+ // ********** initialization **********
+
+ protected PropertyChangeListener buildRootListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildRootListener_());
+ }
+
+ protected PropertyChangeListener buildRootListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ TreeModelAdapter.this.rootChanged();
+ }
+ @Override
+ public String toString() {
+ return "root listener";
+ }
+ };
+ }
+
+ protected PropertyChangeListener buildNodeValueListener() {
+ return new AWTPropertyChangeListenerWrapper(this.buildNodeValueListener_());
+ }
+
+ protected PropertyChangeListener buildNodeValueListener_() {
+ return new PropertyChangeListener() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public void propertyChanged(PropertyChangeEvent event) {
+ TreeModelAdapter.this.nodeChanged((TreeNodeValueModel<T>) event.getSource());
+ }
+ @Override
+ public String toString() {
+ return "node value listener";
+ }
+ };
+ }
+
+ protected StateChangeListener buildNodeStateListener() {
+ return new AWTStateChangeListenerWrapper(this.buildNodeStateListener_());
+ }
+
+ protected StateChangeListener buildNodeStateListener_() {
+ return new StateChangeListener() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public void stateChanged(StateChangeEvent event) {
+ TreeModelAdapter.this.nodeChanged((TreeNodeValueModel<T>) event.getSource());
+ }
+ @Override
+ public String toString() {
+ return "node state listener";
+ }
+ };
+ }
+
+ protected ListChangeListener buildChildrenListener() {
+ return new AWTListChangeListenerWrapper(this.buildChildrenListener_());
+ }
+
+ protected ListChangeListener buildChildrenListener_() {
+ return new ListChangeListener() {
+ @Override
+ public void itemsAdded(ListAddEvent event) {
+ new AddEventChangePolicy(event).addChildren();
+ }
+ @Override
+ public void itemsRemoved(ListRemoveEvent event) {
+ new RemoveEventChangePolicy(event).removeChildren();
+ }
+ @Override
+ public void itemsReplaced(ListReplaceEvent event) {
+ new ReplaceEventChangePolicy(event).replaceChildren();
+ }
+ @Override
+ public void itemsMoved(ListMoveEvent event) {
+ new MoveEventChangePolicy(event).moveChildren();
+ }
+ @Override
+ public void listCleared(ListClearEvent event) {
+ new ClearEventChangePolicy(event).clearChildren();
+ }
+ @Override
+ public void listChanged(ListChangeEvent event) {
+ new ChangeEventChangePolicy(event).rebuildChildren();
+ }
+ @Override
+ public String toString() {
+ return "children listener";
+ }
+ };
+ }
+
+
+ // ********** TreeModel implementation **********
+
+ @Override
+ public Object getRoot() {
+ return this.root;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getChild(Object parent, int index) {
+ return ((TreeNodeValueModel<T>) parent).child(index);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public int getChildCount(Object parent) {
+ return ((TreeNodeValueModel<T>) parent).childrenSize();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean isLeaf(Object node) {
+ return ((TreeNodeValueModel<T>) node).isLeaf();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void valueForPathChanged(TreePath path, Object newValue) {
+ ((TreeNodeValueModel<T>) path.getLastPathComponent()).setValue((T) newValue);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public int getIndexOfChild(Object parent, Object child) {
+ return ((TreeNodeValueModel<T>) parent).indexOfChild((TreeNodeValueModel<T>) child);
+ }
+
+ /**
+ * Extend to start listening to the underlying model if necessary.
+ */
+ @Override
+ public void addTreeModelListener(TreeModelListener l) {
+ if (this.hasNoTreeModelListeners()) {
+ this.engageModel();
+ }
+ super.addTreeModelListener(l);
+ }
+
+ /**
+ * Extend to stop listening to the underlying model if appropriate.
+ */
+ @Override
+ public void removeTreeModelListener(TreeModelListener l) {
+ super.removeTreeModelListener(l);
+ if (this.hasNoTreeModelListeners()) {
+ this.disengageModel();
+ }
+ }
+
+
+ // ********** behavior **********
+
+ /**
+ * Listen to the root and all the other nodes
+ * in the underlying tree model.
+ */
+ private void engageModel() {
+ this.rootHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.rootListener);
+ this.root = this.rootHolder.getValue();
+ if (this.root == null) {
+ throw new NullPointerException(); // the root cannot be null while we have listeners
+ }
+ this.engageNode(this.root);
+ this.addRoot();
+ }
+
+ /**
+ * Add the root and all of the nodes to the underlying tree.
+ */
+ private void addRoot() {
+ this.addNode(0, this.root);
+ }
+
+ /**
+ * Stop listening to the root and all the other
+ * nodes in the underlying tree model.
+ */
+ private void disengageModel() {
+ this.removeRoot();
+ this.disengageNode(this.root);
+ this.root = null;
+ this.rootHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.rootListener);
+ }
+
+ /**
+ * Remove the root and all of the nodes from the underlying tree.
+ */
+ private void removeRoot() {
+ this.removeNode(0, this.root);
+ }
+
+ /**
+ * The root has been swapped.
+ * This method is a bit gnarly because the API for notifying listeners
+ * that the root has changed is a bit inconsistent with that used for
+ * non-root nodes.
+ */
+ void rootChanged() {
+ TreeNodeValueModel<T> newRoot = this.rootHolder.getValue();
+ if (newRoot == null) {
+ throw new NullPointerException(); // the root cannot be null while we have listeners
+ }
+ // remove all the current root's children from the tree
+ // and remove the it from the internal tree
+ this.removeRoot();
+
+ // save the old root and swap in the new 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
+ // because their values can be affected by whether they have listeners
+ this.engageNode(this.root);
+ this.fireTreeRootReplaced(this.root);
+ // now we can stop listening to the old root
+ this.disengageNode(oldRoot);
+
+ // add the new root to the internal tree and
+ // add all its children to the tree also
+ this.addRoot();
+ }
+
+ /**
+ * Either the "value" or the "state" of the specified node has changed,
+ * forward notification to our listeners.
+ */
+ void nodeChanged(TreeNodeValueModel<T> node) {
+ TreeNodeValueModel<T> parent = node.parent();
+ if (parent == null) {
+ this.fireTreeRootChanged(node);
+ } else {
+ this.fireTreeNodeChanged(parent.path(), parent.indexOfChild(node), node);
+ }
+ }
+
+ /**
+ * Listen to the nodes, notify our listeners that the nodes were added,
+ * and then add the nodes to our internal tree.
+ * We must listen to the nodes before notifying anybody, because
+ * adding a listener can change the value of a node.
+ */
+ void addChildren(TreeNodeValueModel<T>[] path, int[] childIndices, TreeNodeValueModel<T>[] children) {
+ int len = childIndices.length;
+ for (int i = 0; i < len; i++) {
+ this.engageNode(children[i]);
+ }
+ this.fireTreeNodesInserted(path, childIndices, children);
+ for (int i = 0; i < len; i++) {
+ this.addNode(childIndices[i], children[i]);
+ }
+ }
+
+ /**
+ * Listen to the node and its children model.
+ */
+ private void engageNode(TreeNodeValueModel<T> node) {
+ node.addStateChangeListener(this.nodeStateListener);
+ node.addPropertyChangeListener(PropertyValueModel.VALUE, this.nodeValueListener);
+ node.childrenModel().addListChangeListener(ListValueModel.LIST_VALUES, this.childrenListener);
+ }
+
+ /**
+ * Add the node to our internal tree;
+ * then recurse down through the node's children,
+ * adding them to the internal tree also.
+ */
+ private void addNode(int index, TreeNodeValueModel<T> node) {
+ this.addNodeToInternalTree(node.parent(), index, node, node.childrenModel());
+ new NodeChangePolicy(node).addChildren();
+ }
+
+ /**
+ * Add the specified node to our internal tree.
+ */
+ 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<T>>();
+ this.childrenLists.put(parent, siblings);
+ }
+ siblings.add(index, node);
+
+ this.parents.put(childrenModel, node);
+ }
+
+ /**
+ * Remove nodes from our internal tree, notify our listeners that the
+ * nodes were removed, then stop listening to the nodes.
+ * We must listen to the nodes until after notifying anybody, because
+ * removing a listener can change the value of a node.
+ */
+ 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, children[i]);
+ }
+ this.fireTreeNodesRemoved(path, childIndices, children);
+ for (int i = 0; i < len; i++) {
+ this.disengageNode(children[i]);
+ }
+ }
+
+ /**
+ * First, recurse down through the node's children,
+ * removing them from our internal tree;
+ * then remove the node itself from our internal tree.
+ */
+ private void removeNode(int index, TreeNodeValueModel<T> node) {
+ new NodeChangePolicy(node).removeChildren();
+ this.removeNodeFromInternalTree(node.parent(), index, node.childrenModel());
+ }
+
+ /**
+ * Remove the specified node from our internal tree.
+ */
+ private void removeNodeFromInternalTree(TreeNodeValueModel<T> parent, int index, ListValueModel<TreeNodeValueModel<T>> childrenModel) {
+ this.parents.remove(childrenModel);
+
+ List<TreeNodeValueModel<T>> siblings = this.childrenLists.get(parent);
+ siblings.remove(index);
+ if (siblings.isEmpty()) {
+ this.childrenLists.remove(parent);
+ }
+ }
+
+ /**
+ * Stop listening to the node and its children model.
+ */
+ private void disengageNode(TreeNodeValueModel<T> node) {
+ node.childrenModel().removeListChangeListener(ListValueModel.LIST_VALUES, this.childrenListener);
+ node.removePropertyChangeListener(PropertyValueModel.VALUE, this.nodeValueListener);
+ node.removeStateChangeListener(this.nodeStateListener);
+ }
+
+ 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));
+ }
+ childrenList.addAll(targetIndex, temp);
+
+ this.fireTreeStructureChanged(parent.path());
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.root);
+ }
+
+
+ // ********** inner classes **********
+
+ /**
+ * Coalesce some of the common change policy behavior.
+ */
+ abstract class ChangePolicy {
+
+ ChangePolicy() {
+ super();
+ }
+
+ /**
+ * Add the current set of children.
+ */
+ void addChildren() {
+ TreeModelAdapter.this.addChildren(this.parent().path(), this.childIndices(), this.childArray());
+ }
+
+ /**
+ * Remove the current set of children.
+ */
+ void removeChildren() {
+ TreeModelAdapter.this.removeChildren(this.parent().path(), this.childIndices(), this.childArray());
+ }
+
+ /**
+ * Return an array of the indices of the current set of children,
+ * which should be contiguous.
+ */
+ int[] childIndices() {
+ return this.buildIndices(this.childrenStartIndex(), this.childrenSize());
+ }
+
+ /**
+ * Return an array of the current set of children.
+ */
+ TreeNodeValueModel<T>[] childArray() {
+ return this.buildArray(this.getChildren(), this.childrenSize());
+ }
+
+ /**
+ * Build an array to hold the elements in the specified iterator.
+ * If they are different sizes, something is screwed up...
+ */
+ TreeNodeValueModel<T>[] buildArray(Iterable<TreeNodeValueModel<T>> elements, int size) {
+ @SuppressWarnings("unchecked")
+ TreeNodeValueModel<T>[] array = new TreeNodeValueModel[size];
+ int i = 0;
+ for (TreeNodeValueModel<T> element : elements) {
+ array[i++] = element;
+ }
+ return array;
+ }
+
+ /**
+ * Return a set of indices, starting at zero and
+ * continuing for the specified size.
+ */
+ int[] buildIndices(int size) {
+ return buildIndices(0, size);
+ }
+
+ /**
+ * Return a set of indices, starting at the specified index and
+ * continuing for the specified size.
+ */
+ int[] buildIndices(int start, int size) {
+ int[] indices = new int[size];
+ int index = start;
+ for (int i = 0; i < size; i++) {
+ indices[i] = index++;
+ }
+ return indices;
+ }
+
+ /**
+ * Return the parent of the current set of children.
+ */
+ abstract TreeNodeValueModel<T> parent();
+
+ /**
+ * Return the starting index for the current set of children.
+ */
+ abstract int childrenStartIndex();
+
+ /**
+ * Return the size of the current set of children.
+ */
+ abstract int childrenSize();
+
+ /**
+ * Return the current set of children.
+ */
+ abstract Iterable<TreeNodeValueModel<T>> getChildren();
+ }
+
+
+ /**
+ * Wraps a ListEvent for adding, removing, replacing,
+ * and changing children.
+ */
+ /* CU private */ abstract class EventChangePolicy
+ extends ChangePolicy
+ {
+ final ListEvent event;
+
+ EventChangePolicy(ListEvent event) {
+ super();
+ this.event = event;
+ }
+
+ /**
+ * Map the ListChangeEvent's source to the corresponding parent.
+ */
+ @Override
+ TreeNodeValueModel<T> parent() {
+ return TreeModelAdapter.this.parents.get(this.event.getSource());
+ }
+ }
+
+
+ /**
+ * Wraps a ListAddEvent for adding children.
+ */
+ /* CU private */ class AddEventChangePolicy
+ extends EventChangePolicy
+ {
+ AddEventChangePolicy(ListAddEvent event) {
+ super(event);
+ }
+
+ private ListAddEvent getEvent() {
+ return (ListAddEvent) this.event;
+ }
+
+ /**
+ * The ListAddEvent's item index is the children start index.
+ */
+ @Override
+ int childrenStartIndex() {
+ return this.getEvent().getIndex();
+ }
+
+ /**
+ * The ListAddEvent's size is the children size.
+ */
+ @Override
+ int childrenSize() {
+ return this.getEvent().getItemsSize();
+ }
+
+ /**
+ * The ListAddEvent's items are the children.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ Iterable<TreeNodeValueModel<T>> getChildren() {
+ return (Iterable<TreeNodeValueModel<T>>) this.getEvent().getItems();
+ }
+ }
+
+
+ /**
+ * Wraps a ListRemoveEvent for adding children.
+ */
+ /* CU private */ class RemoveEventChangePolicy
+ extends EventChangePolicy
+ {
+ RemoveEventChangePolicy(ListRemoveEvent event) {
+ super(event);
+ }
+
+ private ListRemoveEvent getEvent() {
+ return (ListRemoveEvent) this.event;
+ }
+
+ /**
+ * The ListRemoveEvent's item index is the children start index.
+ */
+ @Override
+ int childrenStartIndex() {
+ return this.getEvent().getIndex();
+ }
+
+ /**
+ * The ListRemoveEvent's size is the children size.
+ */
+ @Override
+ int childrenSize() {
+ return this.getEvent().getItemsSize();
+ }
+
+ /**
+ * The ListRemoveEvent's items are the children.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ Iterable<TreeNodeValueModel<T>> getChildren() {
+ return (Iterable<TreeNodeValueModel<T>>) this.getEvent().getItems();
+ }
+ }
+
+
+ /**
+ * Wraps a ListReplaceEvent for replacing children.
+ */
+ /* CU private */ class ReplaceEventChangePolicy
+ extends EventChangePolicy
+ {
+ ReplaceEventChangePolicy(ListReplaceEvent event) {
+ super(event);
+ }
+
+ private ListReplaceEvent getEvent() {
+ return (ListReplaceEvent) this.event;
+ }
+
+ /**
+ * The ListReplaceEvent's item index is the children start index.
+ */
+ @Override
+ int childrenStartIndex() {
+ return this.getEvent().getIndex();
+ }
+
+ /**
+ * The ListReplaceEvent's size is the children size.
+ */
+ @Override
+ int childrenSize() {
+ return this.getEvent().getItemsSize();
+ }
+
+ /**
+ * The ListReplaceEvent's items are the children.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ Iterable<TreeNodeValueModel<T>> getChildren() {
+ return (Iterable<TreeNodeValueModel<T>>) this.getEvent().getNewItems();
+ }
+
+ /**
+ * Remove the old nodes and add the new ones.
+ */
+ void replaceChildren() {
+ TreeNodeValueModel<T>[] parentPath = this.parent().path();
+ int[] childIndices = this.childIndices();
+ TreeModelAdapter.this.removeChildren(parentPath, childIndices, this.getOldChildren());
+ TreeModelAdapter.this.addChildren(parentPath, childIndices, this.childArray());
+ }
+
+ TreeNodeValueModel<T>[] getOldChildren() {
+ return this.buildArray(this.getOldItems(), this.getEvent().getItemsSize());
+ }
+
+ // minimized scope of suppressed warnings
+ @SuppressWarnings("unchecked")
+ protected Iterable<TreeNodeValueModel<T>> getOldItems() {
+ return (Iterable<TreeNodeValueModel<T>>) this.getEvent().getOldItems();
+ }
+ }
+
+
+ /**
+ * Wraps a ListMoveEvent for moving children.
+ */
+ /* CU private */ class MoveEventChangePolicy
+ extends EventChangePolicy
+ {
+ MoveEventChangePolicy(ListMoveEvent event) {
+ super(event);
+ }
+
+ private ListMoveEvent getEvent() {
+ return (ListMoveEvent) this.event;
+ }
+
+ void moveChildren() {
+ TreeModelAdapter.this.moveChildren(this.parent(), this.getEvent().getTargetIndex(), this.getEvent().getSourceIndex(), this.getEvent().getLength());
+ }
+
+ @Override
+ int childrenStartIndex() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ int childrenSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ Iterable<TreeNodeValueModel<T>> getChildren() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+
+ /**
+ * Wraps a ListClearEvent for clearing children.
+ */
+ /* CU private */ class ClearEventChangePolicy
+ extends EventChangePolicy
+ {
+ ClearEventChangePolicy(ListClearEvent event) {
+ super(event);
+ }
+
+ /**
+ * Clear all the nodes.
+ */
+ void clearChildren() {
+ 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());
+ TreeNodeValueModel<T>[] childArray = this.buildArray(childrenList, childrenList.size());
+ TreeModelAdapter.this.removeChildren(parentPath, childIndices, childArray);
+ }
+
+ @Override
+ int childrenStartIndex() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ int childrenSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ Iterable<TreeNodeValueModel<T>> getChildren() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+
+ /**
+ * Wraps a ListChangeEvent for clearing children.
+ */
+ /* CU private */ class ChangeEventChangePolicy
+ extends EventChangePolicy
+ {
+ ChangeEventChangePolicy(ListChangeEvent event) {
+ super(event);
+ }
+
+ /**
+ * Remove all the old nodes and add all the new nodes.
+ */
+ void rebuildChildren() {
+ 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());
+ TreeNodeValueModel<T>[] childArray = this.buildArray(childrenList, childrenList.size());
+ TreeModelAdapter.this.removeChildren(parentPath, childIndices, childArray);
+
+ childIndices = this.buildIndices(parent.childrenModel().size());
+ childArray = this.buildArray(parent.childrenModel(), parent.childrenSize());
+ TreeModelAdapter.this.addChildren(parentPath, childIndices, childArray);
+ }
+
+ @Override
+ int childrenStartIndex() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ int childrenSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ Iterable<TreeNodeValueModel<T>> getChildren() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+
+ /**
+ * Wraps a TreeNodeValueModel for adding and removing its children.
+ */
+ /* CU private */ class NodeChangePolicy
+ extends ChangePolicy
+ {
+ private final TreeNodeValueModel<T> node;
+
+ NodeChangePolicy(TreeNodeValueModel<T> node) {
+ super();
+ this.node = node;
+ }
+
+ /**
+ * The node itself is the parent.
+ */
+ @Override
+ TreeNodeValueModel<T> parent() {
+ return this.node;
+ }
+
+ /**
+ * Since we will always be dealing with all of the node's
+ * children, the children start index is always zero.
+ */
+ @Override
+ int childrenStartIndex() {
+ return 0;
+ }
+
+ /**
+ * Since we will always be dealing with all of the node's
+ * children, the children size is always equal to the size
+ * of the children model.
+ */
+ @Override
+ int childrenSize() {
+ return this.node.childrenModel().size();
+ }
+
+ /**
+ * Since we will always be dealing with all of the node's
+ * children, the children are all the objects held by
+ * the children model.
+ */
+ @Override
+ Iterable<TreeNodeValueModel<T>> getChildren() {
+ return this.node.childrenModel();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CachingComboBoxModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CachingComboBoxModel.java
new file mode 100644
index 0000000..03de5cd
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CachingComboBoxModel.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import javax.swing.ComboBoxModel;
+
+/**
+ * This interface allows a client to better control the performance of
+ * a combo box model by allowing the client to specify when it is
+ * acceptable for the model to "cache" and "uncache" its list of elements.
+ * The model may ignore these hints if appropriate.
+ */
+public interface CachingComboBoxModel
+ extends ComboBoxModel
+{
+ /**
+ * Cache the comboBoxModel List. If you call this, you
+ * must make sure to call uncacheList() as well. Otherwise
+ * stale data will be in the ComboBox until cacheList() is
+ * called again or uncacheList() is called.
+ */
+ void cacheList();
+
+ /**
+ * Clear the cached list. Next time the list is needed it will
+ * be built when it is not cached.
+ */
+ void uncacheList();
+
+ /**
+ * Check to see if the list is already cached. This can be used for
+ * MouseEvents, since they are not terribly predictable.
+ */
+ boolean isCached();
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CheckBoxTableCellRenderer.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CheckBoxTableCellRenderer.java
new file mode 100644
index 0000000..9b174aa
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CheckBoxTableCellRenderer.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.JCheckBox;
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import org.eclipse.persistence.tools.utility.swing.TableCellEditorAdapter.ImmediateEditListener;
+
+/**
+ * Make the cell look like a check box.
+ */
+@SuppressWarnings("nls")
+public class CheckBoxTableCellRenderer
+ implements TableCellEditorAdapter.Renderer
+{
+ /** the component used to paint the cell */
+ private final JCheckBox checkBox;
+
+ /** the listener to be notified on an immediate edit */
+ protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
+
+ /** "normal" border - assume the default table "focus" border is 1 pixel thick */
+ private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
+
+
+ // ********** constructors/initialization **********
+
+ /**
+ * Construct a cell renderer with no label or icon.
+ */
+ public CheckBoxTableCellRenderer() {
+ super();
+ this.checkBox = this.buildCheckBox();
+ // by default, check boxes do not paint their borders
+ this.checkBox.setBorderPainted(true);
+ // this setting is recommended for check boxes inside of trees and tables
+ this.checkBox.setBorderPaintedFlat(true);
+ }
+
+ /**
+ * Construct a cell renderer with the specified text and icon,
+ * either of which may be null.
+ */
+ public CheckBoxTableCellRenderer(String text, Icon icon) {
+ this();
+ this.setText(text);
+ this.setIcon(icon);
+ }
+
+ /**
+ * Construct a cell renderer with the specified text.
+ */
+ public CheckBoxTableCellRenderer(String text) {
+ this(text, null);
+ }
+
+ /**
+ * Construct a cell renderer with the specified icon.
+ */
+ public CheckBoxTableCellRenderer(Icon icon) {
+ this(null, icon);
+ }
+
+ protected JCheckBox buildCheckBox() {
+ JCheckBox cb = new JCheckBox();
+ cb.addActionListener(this.buildActionListener());
+ return cb;
+ }
+
+ private ActionListener buildActionListener() {
+ return new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (CheckBoxTableCellRenderer.this.immediateEditListener != null) {
+ CheckBoxTableCellRenderer.this.immediateEditListener.immediateEdit();
+ }
+ }
+ };
+ }
+
+
+ // ********** TableCellRenderer implementation **********
+
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
+ this.checkBox.setHorizontalAlignment(SwingConstants.CENTER);
+ this.checkBox.setComponentOrientation(table.getComponentOrientation());
+ this.checkBox.setFont(table.getFont());
+ this.checkBox.setEnabled(table.isEnabled());
+
+ this.checkBox.setForeground(this.foregroundColor(table, value, selected, hasFocus, row, column));
+ this.checkBox.setBackground(this.backgroundColor(table, value, selected, hasFocus, row, column));
+ // once the colors are set, calculate opaque setting
+ this.checkBox.setOpaque(this.cellIsOpaqueIn(table, value, selected, hasFocus, row, column));
+ this.checkBox.setBorder(this.border(table, value, selected, hasFocus, row, column));
+
+ this.setValue(value);
+ return this.checkBox;
+ }
+
+ /**
+ * Return the cell's foreground color.
+ */
+ protected Color foregroundColor(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, int row, int column) {
+ if (selected) {
+ if (hasFocus && table.isCellEditable(row, column)) {
+ return UIManager.getColor("Table.focusCellForeground");
+ }
+ return table.getSelectionForeground();
+ }
+ return table.getForeground();
+ }
+
+ /**
+ * Return the cell's background color.
+ */
+ protected Color backgroundColor(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, int row, int column) {
+ if (selected) {
+ if (hasFocus && table.isCellEditable(row, column)) {
+ return UIManager.getColor("Table.focusCellBackground");
+ }
+ return table.getSelectionBackground();
+ }
+ return table.getBackground();
+ }
+
+ /**
+ * Return the cell's border.
+ */
+ protected Border border(@SuppressWarnings("unused") JTable table, @SuppressWarnings("unused") Object value, @SuppressWarnings("unused") boolean selected, boolean hasFocus, @SuppressWarnings("unused") int row, @SuppressWarnings("unused") int column) {
+ return hasFocus ? UIManager.getBorder("Table.focusCellHighlightBorder") : NO_FOCUS_BORDER;
+ }
+
+ /**
+ * Return whether the cell should be opaque in the table.
+ * If the cell's background is the same as the table's background
+ * and table is opaque, we don't need to paint the background -
+ * the table will do it.
+ */
+ protected boolean cellIsOpaqueIn(JTable table, @SuppressWarnings("unused") Object value, @SuppressWarnings("unused") boolean selected, @SuppressWarnings("unused") boolean hasFocus, @SuppressWarnings("unused") int row, @SuppressWarnings("unused") int column) {
+ Color cellBackground = this.checkBox.getBackground();
+ Color tableBackground = table.getBackground();
+ return ! (table.isOpaque() && cellBackground.equals(tableBackground));
+ }
+
+ /**
+ * Set the check box's value.
+ */
+ protected void setValue(Object value) {
+ // CR#3999318 - This null check needs to be removed once JDK bug is fixed
+ if (value == null) {
+ value = Boolean.FALSE;
+ }
+ this.checkBox.setSelected(((Boolean) value).booleanValue());
+ }
+
+
+ // ********** TableCellEditorAdapter.Renderer implementation **********
+
+ @Override
+ public Object getValue() {
+ return Boolean.valueOf(this.checkBox.isSelected());
+ }
+
+ @Override
+ public void setImmediateEditListener(ImmediateEditListener listener) {
+ this.immediateEditListener = listener;
+ }
+
+ // ********** public API **********
+
+ /**
+ * Set the check box's text; which by default is blank.
+ */
+ public void setText(String text) {
+ this.checkBox.setText(text);
+ }
+
+ /**
+ * Set the check box's icon; which by default is not present.
+ */
+ public void setIcon(Icon icon) {
+ this.checkBox.setIcon(icon);
+ }
+
+ /**
+ * Return the renderer's preferred height. This allows you
+ * to set the table's row height to something the check box
+ * will look good in....
+ */
+ public int preferredHeight() {
+ // add in space for the border top and bottom
+ return (int) this.checkBox.getPreferredSize().getHeight() + 2;
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ComboBoxTableCellRenderer.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ComboBoxTableCellRenderer.java
new file mode 100644
index 0000000..cef9904
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ComboBoxTableCellRenderer.java
@@ -0,0 +1,342 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.BorderFactory;
+import javax.swing.ComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JTable;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingConstants;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+
+/**
+ * Make the cell look like a combo-box.
+ */
+@SuppressWarnings("nls")
+public class ComboBoxTableCellRenderer
+ implements TableCellEditorAdapter.Renderer
+{
+ /* caching the combo box because we are caching the comboBoxModel.
+ * Everytime we rebuilt the comboBox we would set the model on it and not
+ * remove the model from the old combo box. This meant that new listeners
+ * kept being added to the comboBoxModel for every comboBox build.
+ * Not sure if there is a way to clear out the old combo box, or why
+ * we were buildig a new combo box every time so I went with caching it.
+ */
+ private JComboBox comboBox;
+
+ /** the items used to populate the combo box */
+ private CachingComboBoxModel model;
+ private ListCellRenderer renderer;
+ Object value;
+ private static int height = -1;
+ boolean fakeFocusFlag;
+
+ /** the listener to be notified on an immediate edit */
+ protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
+
+ /** hold the original colors of the combo-box */
+ private static Color defaultForeground;
+ private static Color defaultBackground;
+
+ /** "normal" border - assume the default table "focus" border is 1 pixel thick */
+ private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
+
+
+ // ********** constructors/initialization **********
+
+ /**
+ * Default constructor.
+ */
+ private ComboBoxTableCellRenderer() {
+ super();
+ initialize();
+ }
+
+ /**
+ * Construct a cell renderer that uses the specified combo-box model.
+ */
+ public ComboBoxTableCellRenderer(ComboBoxModel model) {
+ this(new NonCachingComboBoxModel(model));
+ }
+
+ /**
+ * Construct a cell renderer that uses the specified caching combo-box model.
+ */
+ public ComboBoxTableCellRenderer(CachingComboBoxModel model) {
+ this();
+ this.model = model;
+ }
+
+ /**
+ * Construct a cell renderer that uses the specified
+ * combo-box model and renderer.
+ */
+ public ComboBoxTableCellRenderer(ComboBoxModel model, ListCellRenderer renderer) {
+ this(new NonCachingComboBoxModel(model), renderer);
+ }
+
+ /**
+ * Construct a cell renderer that uses the specified
+ * caching combo-box model and renderer.
+ */
+ public ComboBoxTableCellRenderer(CachingComboBoxModel model, ListCellRenderer renderer) {
+ this(model);
+ this.renderer = renderer;
+ }
+
+ protected void initialize() {
+ // save the original colors of the combo-box, so we
+ // can use them to paint non-selected cells
+ if (height == -1) {
+ JComboBox cb = new JComboBox();
+ cb.addItem("m");
+
+ // add in space for the border top and bottom
+ height = cb.getPreferredSize().height + 2;
+
+ defaultForeground = cb.getForeground();
+ defaultBackground = cb.getBackground();
+ }
+ }
+
+ static JLabel prototypeLabel = new JLabel("Prototype", new EmptyIcon(16), SwingConstants.LEADING);
+
+ protected JComboBox buildComboBox() {
+
+ final JComboBox result = new JComboBox() {
+ private boolean fakeFocus;
+ private static final long serialVersionUID = 1L;
+ @Override
+ public boolean hasFocus() {
+ return this.fakeFocus || super.hasFocus();
+ }
+ @Override
+ public void paint(Graphics g) {
+ this.fakeFocus = ComboBoxTableCellRenderer.this.fakeFocusFlag;
+ super.paint(g);
+ this.fakeFocus = false;
+ }
+ //wrap the renderer to deal with the prototypeDisplayValue
+ @Override
+ public void setRenderer(final ListCellRenderer aRenderer) {
+ super.setRenderer(new ListCellRenderer(){
+ @Override
+ public Component getListCellRendererComponent(JList list, Object v, int index, boolean isSelected, boolean cellHasFocus) {
+ if (v == prototypeLabel) {
+ return prototypeLabel;
+ }
+ return aRenderer.getListCellRendererComponent(list, v, index, isSelected, cellHasFocus);
+ }
+ });
+ }
+ @Override
+ public int getSelectedIndex() {
+ boolean listNotCached = !listIsCached();
+ if (listNotCached) {
+ cacheList();
+ }
+
+ int index = super.getSelectedIndex();
+
+ if (listNotCached) {
+ uncacheList();
+ }
+ return index;
+ }
+
+ };
+ // stole this code from javax.swing.DefaultCellEditor
+ result.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
+ result.addActionListener(this.buildActionListener());
+ result.addPopupMenuListener(this.buildPopupMenuListener());
+
+ //These are used to workaround problems with Swing trying to
+ //determine the size of a comboBox with a large model
+ result.setPrototypeDisplayValue(prototypeLabel);
+ getListBox(result).setPrototypeCellValue(prototypeLabel);
+
+ return result;
+ }
+
+
+ private JList getListBox(JComboBox result) {
+ return (JList) ObjectTools.get(result.getUI(), "listBox");
+ }
+
+
+ private ActionListener buildActionListener() {
+ return new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JComboBox cb = (JComboBox) e.getSource();
+ Object selectedItem = cb.getSelectedItem();
+
+ // Only update the selected item and invoke immediateEdit() if the
+ // selected item actually changed, during the initialization of the
+ // editing, the model changes and causes this method to be invoked,
+ // it causes CR#3963675 to occur because immediateEdit() stop the
+ // editing, which is done at the wrong time
+ if (ComboBoxTableCellRenderer.this.value != selectedItem) {
+ ComboBoxTableCellRenderer.this.value = cb.getSelectedItem();
+ ComboBoxTableCellRenderer.this.immediateEdit();
+ }
+ }
+ };
+ }
+
+ void immediateEdit() {
+ if (this.immediateEditListener != null) {
+ this.immediateEditListener.immediateEdit();
+ }
+ }
+
+ private PopupMenuListener buildPopupMenuListener() {
+ return new PopupMenuListener() {
+
+ @Override
+ public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+ if (listIsCached()) {
+ uncacheList();
+ }
+ cacheList();
+ }
+
+ @Override
+ public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+ if (listIsCached()) {
+ uncacheList();
+ }
+
+ }
+
+ @Override
+ public void popupMenuCanceled(PopupMenuEvent e) {
+ if (listIsCached()) {
+ uncacheList();
+ }
+ }
+ };
+ }
+
+
+ void cacheList() {
+ this.model.cacheList();
+ }
+
+ void uncacheList() {
+ this.model.uncacheList();
+ }
+
+ boolean listIsCached() {
+ return this.model.isCached();
+ }
+ // ********** TableCellRenderer implementation **********
+
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object val, boolean selected, boolean hasFocus, int row, int column) {
+ this.fakeFocusFlag = selected || hasFocus;
+ if (this.comboBox == null) {
+ this.comboBox = this.buildComboBox();
+
+ this.comboBox.setComponentOrientation(table.getComponentOrientation());
+ this.comboBox.setModel(this.model);
+ if (this.renderer != null) {
+ this.comboBox.setRenderer(this.renderer);
+ }
+ this.comboBox.setFont(table.getFont());
+ this.comboBox.setEnabled(table.isEnabled());
+ this.comboBox.setBorder(this.border(table, val, selected, hasFocus, row, column));
+ }
+
+ // We need to go through the model since JComboBox might prevent us from
+ // selecting the value. This can happen when the value is not contained
+ // in the model, see CR#3950044 for an example
+ this.model.setSelectedItem(val);
+
+ return this.comboBox;
+ }
+
+ /**
+ * Return the cell's foreground color.
+ */
+ protected Color foregroundColor(JTable table, @SuppressWarnings("unused") Object val, boolean selected, boolean hasFocus, int row, int column) {
+ if (selected) {
+ if (hasFocus && table.isCellEditable(row, column)) {
+ return defaultForeground;
+ }
+ return table.getSelectionForeground();
+ }
+ return defaultForeground;
+ }
+
+ /**
+ * Return the cell's background color.
+ */
+ protected Color backgroundColor(JTable table, @SuppressWarnings("unused") Object val, boolean selected, boolean hasFocus, int row, int column) {
+ if (selected) {
+ if (hasFocus && table.isCellEditable(row, column)) {
+ return defaultBackground;
+ }
+ return table.getSelectionBackground();
+ }
+ return defaultBackground;
+ }
+
+ /**
+ * Return the cell's border.
+ */
+ protected Border border(@SuppressWarnings("unused") JTable table, @SuppressWarnings("unused") Object val, @SuppressWarnings("unused") boolean selected, boolean hasFocus, @SuppressWarnings("unused") int row, @SuppressWarnings("unused") int column) {
+ return hasFocus ?
+ UIManager.getBorder("Table.focusCellHighlightBorder") //$NON-NLS-1$
+ :
+ NO_FOCUS_BORDER;
+ }
+
+
+ // ********** TableCellEditorAdapter.Renderer implementation **********
+
+ @Override
+ public Object getValue() {
+ return this.value;
+ }
+
+ @Override
+ public void setImmediateEditListener(TableCellEditorAdapter.ImmediateEditListener listener) {
+ this.immediateEditListener = listener;
+ }
+
+
+ // ********** public API **********
+
+ /**
+ * 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 preferredHeight() {
+ return height;
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/EmptyIcon.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/EmptyIcon.java
new file mode 100644
index 0000000..9d3f076
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/EmptyIcon.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import javax.swing.Icon;
+
+/**
+ * Implement the {@link Icon} interface with an icon that has a size but
+ * does not paint anything on the graphics context.
+ */
+public class EmptyIcon
+ implements Icon
+{
+ private final int width;
+ private final int height;
+
+ public static final EmptyIcon NULL_INSTANCE = new EmptyIcon(0);
+
+
+ public EmptyIcon(int size) {
+ this(size, size);
+ }
+
+ public EmptyIcon(int width, int height) {
+ super();
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public void paintIcon(Component c, Graphics g, int x, int y) {
+ // don't paint anything for an empty icon
+ }
+
+ @Override
+ public int getIconWidth() {
+ return this.width;
+ }
+
+ @Override
+ public int getIconHeight() {
+ return this.height;
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListBrowser.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListBrowser.java
new file mode 100644
index 0000000..2721830
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListBrowser.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import javax.swing.Icon;
+import javax.swing.JComboBox;
+import javax.swing.JOptionPane;
+import javax.swing.ListModel;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+
+/**
+ * This implementation of ListChooser.ListBrowser uses a
+ * {@link JOptionPane} to prompt the user for the selection. The {@link JOptionPane}
+ * is passed a {@link FilteringListPanel} to assist the user in making
+ * a selection.
+ */
+@SuppressWarnings("nls")
+public class FilteringListBrowser<T>
+ implements ListChooser.ListBrowser
+{
+ private FilteringListPanel<T> panel;
+
+ /**
+ * Default constructor.
+ */
+ public FilteringListBrowser() {
+ super();
+ this.panel = this.buildPanel();
+ }
+
+ protected FilteringListPanel<T> buildPanel() {
+ return new LocalFilteringListPanel<T>();
+ }
+
+ /**
+ * Prompt the user using a JOptionPane with a filtering
+ * list panel.
+ */
+ @Override
+ public void browse(ListChooser chooser) {
+ this.initializeCellRenderer(chooser);
+
+ int option =
+ JOptionPane.showOptionDialog(
+ chooser,
+ this.buildMessage(chooser),
+ this.buildTitle(chooser),
+ this.buildOptionType(chooser),
+ this.buildMessageType(chooser),
+ this.buildIcon(chooser),
+ this.buildSelectionValues(chooser),
+ this.buildInitialSelectionValue(chooser)
+ );
+
+ if (option == JOptionPane.OK_OPTION) {
+ chooser.getModel().setSelectedItem(this.panel.getSelection());
+ }
+
+ // clear the text field so the list box is re-filtered
+ this.panel.getTextField().setText("");
+ }
+
+ protected void initializeCellRenderer(JComboBox comboBox) {
+ // default behavior should be to use the cell renderer from the combobox.
+ this.panel.getListBox().setCellRenderer(comboBox.getRenderer());
+ }
+
+ /**
+ * the message can be anything - here we build a component
+ */
+ protected Object buildMessage(JComboBox comboBox) {
+ this.panel.setCompleteList(this.convertListModelToArray(comboBox.getModel()));
+ this.panel.setSelection(comboBox.getModel().getSelectedItem());
+ return this.panel;
+ }
+
+ /**
+ * Convert the list of objects in the specified list model
+ * into an array.
+ */
+ @SuppressWarnings("unchecked")
+ protected T[] convertListModelToArray(ListModel model) {
+ int size = model.getSize();
+ T[] result = (T[]) new Object[size];
+ for (int i = 0; i < size; i++) {
+ result[i] = (T) model.getElementAt(i);
+ }
+ return result;
+ }
+
+ protected String buildTitle(@SuppressWarnings("unused") JComboBox comboBox) {
+ return null;
+ }
+
+ protected int buildOptionType(@SuppressWarnings("unused") JComboBox comboBox) {
+ return JOptionPane.OK_CANCEL_OPTION;
+ }
+
+ protected int buildMessageType(@SuppressWarnings("unused") JComboBox comboBox) {
+ return JOptionPane.QUESTION_MESSAGE;
+ }
+
+ protected Icon buildIcon(@SuppressWarnings("unused") JComboBox comboBox) {
+ return null;
+ }
+
+ protected Object[] buildSelectionValues(@SuppressWarnings("unused") JComboBox comboBox) {
+ return null;
+ }
+
+ protected Object buildInitialSelectionValue(@SuppressWarnings("unused") JComboBox comboBox) {
+ return null;
+ }
+
+
+ // ********** custom panel **********
+
+ protected static class LocalFilteringListPanel<S>
+ extends FilteringListPanel<S>
+ {
+ private static final long serialVersionUID = 1L;
+
+ @SuppressWarnings("unchecked")
+ protected LocalFilteringListPanel() {
+ super((S[]) ObjectTools.EMPTY_OBJECT_ARRAY, null);
+ }
+
+ /**
+ * Disable the performance tweak because JOptionPane
+ * will try open wide enough to disable the horizontal scroll bar;
+ * and it looks a bit clumsy.
+ */
+ @Override
+ protected String getPrototypeCellValue() {
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListPanel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListPanel.java
new file mode 100644
index 0000000..b01566d
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListPanel.java
@@ -0,0 +1,459 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import javax.swing.AbstractListModel;
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListModel;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.Border;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.StringMatcher;
+import org.eclipse.persistence.tools.utility.transformer.StringObjectTransformer;
+import org.eclipse.persistence.tools.utility.transformer.Transformer;
+
+/**
+ * This panel presents an entry field and a list box of choices that
+ * allows the user to filter the entries in the list box by entering
+ * a pattern in the entry field.
+ * <p>
+ * Two wildcards are allowed in the pattern:<ul>
+ * <li>'*' will match any set of zero or more characters
+ * <li>'?' will match any single character
+ * <.ul>
+ * The panel consists of 4 components that can be customized:<ul>
+ * <li>1 text field
+ * <li>1 list box
+ * <li>2 labels, one for each of the above
+ * </ul>
+ * Other aspects of the panel's behavior can be changed:<ul>
+ * <li>the string converter determines how the objects in the
+ * list are converted to strings and compared to the pattern
+ * entered in the text field; by default the converter simply
+ * uses the result of the object's #toString() method
+ * (if you replace the string converter, you will probably
+ * want to replace the list box's cell renderer also)
+ * <li>the string matcher can also be changed if you would
+ * like different pattern matching behavior than that
+ * described above
+ * <li>you can specify the maximum size of the list - this may
+ * force the user to enter a pattern restrictive enough
+ * to result in a list smaller than the maximum size; the
+ * default is -1, which disables the restriction
+ * </ul>
+ * This panel is not a typical panel, in the sense that it does not share
+ * its model with clients via value models. Instead, this panel's model
+ * is set and queried directly because it is designed to be used in a
+ * dialog that directs the user's behavior (as opposed to a "normal"
+ * window).
+ */
+@SuppressWarnings("nls")
+public class FilteringListPanel<T>
+ extends JPanel
+{
+ /**
+ * The complete list of available choices
+ * (as opposed to the partial list held by the list box).
+ */
+ private T[] completeList;
+
+ /**
+ * An adapter used to convert the objects in the list
+ * to strings so they can be run through the matcher
+ * and displayed in the text field.
+ */
+ Transformer<T, String> transformer;
+
+ /** The text field. */
+ private JTextField textField;
+ private JLabel textFieldLabel;
+ private DocumentListener textFieldListener;
+
+ /** The list box. */
+ private JList listBox;
+ private JLabel listBoxLabel;
+
+ /** The maximum number of entries displayed in the list box. */
+ private int maxListSize;
+
+ /**
+ * Performance tweak: We use this buffer instead of
+ * a temporary variable during filtering so we don't have
+ * to keep re-allocating it.
+ */
+ private Object[] buffer;
+
+ private static final Border TEXT_FIELD_LABEL_BORDER = BorderFactory.createEmptyBorder(0, 0, 5, 0);
+ private static final Border LIST_BOX_LABEL_BORDER = BorderFactory.createEmptyBorder(5, 0, 5, 0);
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Construct a FilteringListPanel with the specified list of choices
+ * and initial selection. Use the default string converter to convert the
+ * choices and selection to strings (which simply calls #toString() on
+ * the objects).
+ */
+ public FilteringListPanel(T[] completeList, T initialSelection) {
+ this(completeList, initialSelection, StringObjectTransformer.<T>instance());
+ }
+
+ /**
+ * Construct a FilteringListPanel with the specified list of choices
+ * and initial selection. Use the specified string converter to convert the
+ * choices and selection to strings.
+ */
+ public FilteringListPanel(T[] completeList, T initialSelection, Transformer<T, String> stringConverter) {
+ super(new BorderLayout());
+ this.completeList = completeList;
+ this.transformer = stringConverter;
+ this.initialize(initialSelection);
+ }
+
+
+ // ********** initialization **********
+
+ private void initialize(T initialSelection) {
+ this.maxListSize = this.getDefaultMaxListSize();
+ this.buffer = this.buildBuffer();
+
+ this.textFieldListener = this.buildTextFieldListener();
+
+ this.initializeLayout(initialSelection);
+ }
+
+ private Object[] buildBuffer() {
+ return new Object[this.getMax()];
+ }
+
+ /**
+ * Return the current max number of entries allowed in the list box.
+ */
+ private int getMax() {
+ return (this.maxListSize == -1) ?
+ this.completeList.length :
+ Math.min(this.maxListSize, this.completeList.length);
+ }
+
+ /**
+ * Build a listener that will listen to changes in the text field
+ * and filter the list appropriately.
+ */
+ private DocumentListener buildTextFieldListener() {
+ return new TextFieldListener();
+ }
+
+ /* CU private */ class TextFieldListener
+ implements DocumentListener
+ {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ FilteringListPanel.this.filterList();
+ }
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ FilteringListPanel.this.filterList();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ FilteringListPanel.this.filterList();
+ }
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+
+ private int getDefaultMaxListSize() {
+ return -1;
+ }
+
+ private void initializeLayout(Object initialSelection) {
+ // text field
+ JPanel textFieldPanel = new JPanel(new BorderLayout());
+ this.textFieldLabel = new JLabel();
+ this.textFieldLabel.setBorder(TEXT_FIELD_LABEL_BORDER);
+ textFieldPanel.add(this.textFieldLabel, BorderLayout.NORTH);
+
+ this.textField = new JTextField();
+ this.textField.getDocument().addDocumentListener(this.textFieldListener);
+ this.textFieldLabel.setLabelFor(this.textField);
+ textFieldPanel.add(this.textField, BorderLayout.CENTER);
+
+ this.add(textFieldPanel, BorderLayout.NORTH);
+
+ // list box
+ JPanel listBoxPanel = new JPanel(new BorderLayout());
+ this.listBoxLabel = new JLabel();
+ this.listBoxLabel.setBorder(LIST_BOX_LABEL_BORDER);
+ listBoxPanel.add(this.listBoxLabel, BorderLayout.NORTH);
+
+ this.listBox = new JList();
+ this.listBox.setDoubleBuffered(true);
+ this.listBox.setModel(this.buildPartialArrayListModel(this.completeList, this.getMax()));
+ this.listBox.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ // performance tweak(?)
+ this.listBox.setPrototypeCellValue(this.getPrototypeCellValue());
+ this.listBox.setPrototypeCellValue(null);
+ this.listBox.setCellRenderer(this.buildDefaultCellRenderer());
+ this.listBoxLabel.setLabelFor(this.listBox);
+ // bug 2777802 - scroll bars shouldn't be on the tab sequence
+ JScrollPane listBoxScrollPane = new JScrollPane(this.listBox);
+ listBoxScrollPane.getHorizontalScrollBar().setFocusable(false);
+ listBoxScrollPane.getVerticalScrollBar().setFocusable(false);
+ listBoxPanel.add(listBoxScrollPane, BorderLayout.CENTER);
+
+ // initialize the widgets
+ this.listBox.setSelectedValue(initialSelection, true);
+ this.textField.select(0, this.textField.getText().length());
+
+ this.add(listBoxPanel, BorderLayout.CENTER);
+ }
+
+
+ // ********** public API **********
+
+ public Object getSelection() {
+ return this.listBox.getSelectedValue();
+ }
+
+ public void setSelection(Object selection) {
+ this.listBox.setSelectedValue(selection, true);
+ }
+
+ public T[] getCompleteList() {
+ return this.completeList;
+ }
+
+ /**
+ * rebuild the filtering buffer and re-apply the filter
+ * to the new list
+ */
+ public void setCompleteList(T[] completeList) {
+ this.completeList = completeList;
+ if (this.buffer.length < this.getMax()) {
+ // the buffer will never shrink - might want to re-consider... ~bjv
+ this.buffer = this.buildBuffer();
+ }
+ this.filterList();
+ }
+
+ public int getMaxListSize() {
+ return this.maxListSize;
+ }
+
+ public void setMaxListSize(int maxListSize) {
+ this.maxListSize = maxListSize;
+ if (this.buffer.length < this.getMax()) {
+ // the buffer will never shrink - might want to re-consider... ~bjv
+ this.buffer = this.buildBuffer();
+ }
+ this.filterList();
+ }
+
+ public Transformer<T, String> getTransformer() {
+ return this.transformer;
+ }
+
+ /**
+ * apply the new filter to the list
+ */
+ public void setTransformer(Transformer<T, String> transformer) {
+ this.transformer = transformer;
+ this.filterList();
+ }
+
+ /**
+ * allow client code to access the text field
+ * (so we can set the focus)
+ */
+ public JTextField getTextField() {
+ return this.textField;
+ }
+
+ /**
+ * allow client code to access the text field label
+ */
+ public JLabel getTextFieldLabel() {
+ return this.textFieldLabel;
+ }
+
+ /**
+ * convenience method
+ */
+ public void setTextFieldLabelText(String text) {
+ this.textFieldLabel.setText(text);
+ }
+
+ /**
+ * allow client code to access the list box
+ * (so we can add mouse listeners for double-clicking)
+ */
+ public JList getListBox() {
+ return this.listBox;
+ }
+
+ /**
+ * convenience method
+ */
+ public void setListBoxCellRenderer(ListCellRenderer renderer) {
+ this.listBox.setCellRenderer(renderer);
+ }
+
+ /**
+ * allow client code to access the list box label
+ */
+ public JLabel getListBoxLabel() {
+ return this.listBoxLabel;
+ }
+
+ /**
+ * convenience method
+ */
+ public void setListBoxLabelText(String text) {
+ this.listBoxLabel.setText(text);
+ }
+
+ /**
+ * convenience method
+ */
+ public void setComponentsFont(Font font) {
+ this.textFieldLabel.setFont(font);
+ this.textField.setFont(font);
+ this.listBoxLabel.setFont(font);
+ this.listBox.setFont(font);
+ }
+
+
+ // ********** internal methods **********
+
+ /**
+ * Allow subclasses to disable performance tweak
+ * by returning null here.
+ */
+ protected String getPrototypeCellValue() {
+ return "==========> A_STRING_THAT_IS_DEFINITELY_LONGER_THAN_EVERY_STRING_IN_THE_LIST <==========";
+ }
+
+ /**
+ * By default, use the string converter to build the text
+ * used by the list box's cell renderer.
+ */
+ protected ListCellRenderer buildDefaultCellRenderer() {
+ return new DefaultCellRenderer();
+ }
+
+ protected class DefaultCellRenderer
+ extends SimpleListCellRenderer
+ {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected String buildText(Object value) {
+ return FilteringListPanel.this.transformer.transform((T) value);
+ }
+ }
+
+ /**
+ * Something has changed that requires us to filter the list.
+ * <p>
+ * This method is synchronized because a fast typist can
+ * generate events quicker than we can filter the list. (? ~bjv)
+ */
+ synchronized void filterList() {
+ // temporarily stop listening to the list box selection, since we will
+ // be changing the selection during the filtering and don't want
+ // that to affect the text field
+ this.filterList(this.textField.getText());
+ }
+
+ /**
+ * Filter the contents of the list box to match the
+ * specified pattern.
+ */
+ private void filterList(String pattern) {
+ if (pattern.length() == 0) {
+ this.listBox.setModel(this.buildPartialArrayListModel(this.completeList, this.getMax()));
+ } else {
+ StringMatcher stringMatcher = new StringMatcher(pattern + ALL, true, false);
+ int j = 0;
+ int len = this.completeList.length;
+ int max = this.getMax();
+ for (int i = 0; i < len; i++) {
+ if (stringMatcher.match(this.transformer.transform(this.completeList[i]))) {
+ this.buffer[j++] = this.completeList[i];
+ }
+ if (j == max) {
+ break;
+ }
+ }
+ this.listBox.setModel(this.buildPartialArrayListModel(this.buffer, j));
+ }
+
+ // after filtering the list, determine the appropriate selection
+ if (this.listBox.getModel().getSize() == 0) {
+ this.listBox.getSelectionModel().clearSelection();
+ } else {
+ this.listBox.getSelectionModel().setAnchorSelectionIndex(0);
+ this.listBox.getSelectionModel().setLeadSelectionIndex(0);
+ this.listBox.ensureIndexIsVisible(0);
+ }
+ }
+ private static final String ALL = "*";
+
+ /**
+ * 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).
+ */
+ private ListModel buildPartialArrayListModel(Object[] array, int size) {
+ return new PartialArrayListModel<T>(array, size);
+ }
+
+ /* CU private */ static class PartialArrayListModel<T>
+ extends AbstractListModel
+ {
+ private final Object[] array;
+ private final int size;
+ private static final long serialVersionUID = 1L;
+
+ PartialArrayListModel(Object[] array, int size) {
+ super();
+ this.array = array;
+ this.size = size;
+ }
+ @Override
+ public int getSize() {
+ return this.size;
+ }
+ @Override
+ @SuppressWarnings("unchecked")
+ public T getElementAt(int index) {
+ return (T) this.array[index];
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ListChooser.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ListChooser.java
new file mode 100644
index 0000000..5335e3c
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ListChooser.java
@@ -0,0 +1,482 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.AWTEvent;
+import java.awt.AWTException;
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.io.Serializable;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingConstants;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import javax.swing.plaf.basic.BasicComboBoxUI;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+
+/**
+ * This component provides a way to handle selecting an item from a
+ * list that may grow too large to be handled conveniently by a combo-box.
+ * If the list's size is less than the designated "long" list size,
+ * the choice list will be displayed in a normal combo-box popup;
+ * otherwise, a dialog will be used to prompt the user to choose a selection.
+ *
+ * To change the browse mechanism, subclasses may
+ * - override the method #buildBrowser()
+ * - override the method #browse(), in which case the method
+ * #buildBrowser() may be ignored.
+ */
+@SuppressWarnings("nls")
+public class ListChooser
+ extends JComboBox
+{
+ /** the size of a "long" list - anything smaller is a "short" list */
+ int longListSize = DEFAULT_LONG_LIST_SIZE;
+
+ /** the default size of a "long" list, which is 20 (to match JOptionPane's behavior) */
+ public static final int DEFAULT_LONG_LIST_SIZE = 20;
+
+ /** property change associated with long list size */
+ public static final String LONG_LIST_SIZE_PROPERTY = "longListSize";
+
+ static JLabel prototypeLabel = new JLabel("Prototype", new EmptyIcon(17), SwingConstants.LEADING);
+
+ /**
+ * whether the chooser is choosable. if a chooser is not choosable,
+ * it only serves as a display widget. a user may not change its
+ * selected value.
+ */
+ boolean choosable = true;
+
+ /** property change associated with choosable */
+ public static final String CHOOSABLE_PROPERTY = "choosable";
+
+ /** the browser used to make a selection from the long list - typically via a dialog */
+ private ListBrowser browser;
+
+ private NodeSelector nodeSelector;
+
+ /** INTERNAL - The popup is being shown. Used to prevent infinite loop. */
+ boolean popupAlreadyInProgress;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // **************** Constructors ******************************************
+
+ /**
+ * Construct a list chooser for the specified model.
+ */
+ public ListChooser(ComboBoxModel model) {
+ this(model, NodeSelector.Default.instance());
+ }
+
+ public ListChooser(CachingComboBoxModel model) {
+ this(model, NodeSelector.Default.instance());
+ }
+
+ public ListChooser(ComboBoxModel model, NodeSelector nodeSelector) {
+ this(new NonCachingComboBoxModel(model), nodeSelector);
+ }
+
+ public ListChooser(CachingComboBoxModel model, NodeSelector nodeSelector) {
+ super(model);
+ this.initialize();
+ this.nodeSelector = nodeSelector;
+ }
+ // **************** Initialization ****************************************
+
+ protected void initialize() {
+ this.addPopupMenuListener(this.buildPopupMenuListener());
+ this.setRenderer(new DefaultListCellRenderer());
+ this.addKeyListener(this.buildF3KeyListener());
+
+ //These are used to workaround problems with Swing trying to
+ //determine the size of a comboBox with a large model
+ this.setPrototypeDisplayValue(prototypeLabel);
+ this.listBox().setPrototypeCellValue(prototypeLabel);
+ }
+
+
+ private JList listBox() {
+ return (JList) ObjectTools.get(this.ui, "listBox");
+ }
+
+ /**
+ * When the popup is about to be shown, the event is consumed, and
+ * PopupHandler determines whether to reshow the popup or to show
+ * the long list browser.
+ */
+ private PopupMenuListener buildPopupMenuListener() {
+ return new PopupMenuListener() {
+ @Override
+ public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+ ListChooser.this.aboutToShowPopup();
+ }
+ @Override
+ public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+ // do nothing
+ }
+ @Override
+ public void popupMenuCanceled(PopupMenuEvent e) {
+ // do nothing
+ }
+ @Override
+ public String toString() {
+ return "pop-up menu listener";
+ }
+ };
+ }
+
+ /**
+ * If this code is being reached due to the PopupHandler already being in progress,
+ * then do nothing. Otherwise, set the flag to true and launch the PopupHandler.
+ */
+ void aboutToShowPopup() {
+ if (this.popupAlreadyInProgress) {
+ return;
+ }
+
+ this.popupAlreadyInProgress = true;
+ EventQueue.invokeLater(new PopupHandler());
+ }
+
+
+ private KeyListener buildF3KeyListener() {
+ return new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_F3) {
+ ListChooser.this.goToSelectedItem();
+ }
+ }
+ @Override
+ public String toString() {
+ return "F3 key listener";
+ }
+ };
+ }
+
+ public void goToSelectedItem() {
+ if (this.getSelectedItem() != null) {
+ ListChooser.this.nodeSelector.selectNodeFor(this.getSelectedItem());
+ }
+ }
+
+ // **************** Browsing **********************************************
+
+ /**
+ * Lazily initialize because subclasses may have further initialization to do
+ * before browser can be built.
+ */
+ protected void browse() {
+ if (this.browser == null) {
+ this.browser = this.buildBrowser();
+ }
+
+ this.browser.browse(this);
+ }
+
+ /**
+ * Return the "browser" used to make a selection from the long list,
+ * typically via a dialog.
+ */
+ protected ListChooser.ListBrowser buildBrowser() {
+ return new SimpleListBrowser();
+ }
+
+
+ // **************** Choosable functionality *******************************
+
+ /** override behavior - consume selection if chooser is not choosable */
+ @Override
+ public void setSelectedIndex(int anIndex) {
+ if (this.choosable) {
+ super.setSelectedIndex(anIndex);
+ }
+ }
+
+ private void updateArrowButton() {
+ try {
+ BasicComboBoxUI comboBoxUi = (BasicComboBoxUI) ListChooser.this.getUI();
+ JButton arrowButton = (JButton) ObjectTools.get(comboBoxUi, "arrowButton");
+ arrowButton.setEnabled(this.isEnabled() && this.choosable);
+ }
+ catch (Exception e) {
+ // this is a huge hack to try and make the combo box look right,
+ // so if it doesn't work, just swallow the exception
+ }
+ }
+
+
+ // **************** List Caching *******************************
+
+ void cacheList() {
+ ((CachingComboBoxModel) this.getModel()).cacheList();
+ }
+
+ void uncacheList() {
+ ((CachingComboBoxModel) this.getModel()).uncacheList();
+ }
+
+ boolean listIsCached() {
+ return ((CachingComboBoxModel) this.getModel()).isCached();
+ }
+
+ // **************** Public ************************************************
+
+ public int longListSize() {
+ return this.longListSize;
+ }
+
+ public void setLongListSize(int newLongListSize) {
+ int oldLongListSize = this.longListSize;
+ this.longListSize = newLongListSize;
+ this.firePropertyChange(LONG_LIST_SIZE_PROPERTY, oldLongListSize, newLongListSize);
+ }
+
+ public boolean isChoosable() {
+ return this.choosable;
+ }
+
+ public void setChoosable(boolean newValue) {
+ boolean oldValue = this.choosable;
+ this.choosable = newValue;
+ this.firePropertyChange(CHOOSABLE_PROPERTY, oldValue, newValue);
+ this.updateArrowButton();
+ }
+
+ // **************** Handle selecting null as a value **********************
+
+ private boolean selectedIndexIsNoneSelectedItem(int index) {
+ return (index == -1) &&
+ (this.getModel().getSize() > 0) &&
+ (this.getModel().getElementAt(0) == null);
+ }
+
+ @Override
+ public int getSelectedIndex() {
+ boolean listNotCached = !this.listIsCached();
+ if (listNotCached) {
+ this.cacheList();
+ }
+
+ int index = super.getSelectedIndex();
+
+ // Use index 0 to show the <none selected> item since the actual value is
+ // null and JComboBox does not handle null values
+ if (this.selectedIndexIsNoneSelectedItem(index)) {
+ index = 0;
+ }
+
+ if (listNotCached) {
+ this.uncacheList();
+ }
+ return index;
+ }
+
+ //wrap the renderer to deal with the prototypeDisplayValue
+ @Override
+ public void setRenderer(final ListCellRenderer aRenderer) {
+ super.setRenderer(new ListCellRenderer(){
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ if (value == prototypeLabel) {
+ return prototypeLabel;
+ }
+ return aRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+ }
+ });
+ }
+
+
+ // **************** Member classes ****************************************
+
+ /**
+ * Define the API required by this ListChooser when it must
+ * prompt the user to select an item from the "long" list.
+ */
+ public interface ListBrowser
+ {
+ /**
+ * Prompt the user to make a selection from the specified
+ * combo-box's model.
+ */
+ void browse(ListChooser parentChooser);
+ }
+
+
+ /**
+ * Runnable class that consumes popup window and determines whether
+ * to reshow popup or to launch browser, based on the size of the list.
+ */
+ private class PopupHandler
+ implements Runnable
+ {
+ /** The mouse event */
+ private MouseEvent lastMouseEvent;
+
+ /** The component from which the last mouse event was thrown */
+ private JComponent eventComponent;
+
+ /** The location of the component at the time the last mouse event was thrown */
+ private Point componentLocation;
+
+ /** The location of the mouse at the time the last mouse event was thrown */
+ private Point mouseLocation;
+
+
+ PopupHandler() {
+ this.initialize();
+ }
+
+ private void initialize() {
+ AWTEvent event = EventQueue.getCurrentEvent();
+
+ if (event instanceof MouseEvent) {
+ this.lastMouseEvent = (MouseEvent) event;
+ this.eventComponent = (JComponent) this.lastMouseEvent.getSource();
+ this.componentLocation = this.eventComponent.getLocationOnScreen();
+ this.mouseLocation = this.lastMouseEvent.getPoint();
+ }
+ else {
+ this.eventComponent = null;
+ this.componentLocation = null;
+ this.mouseLocation = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ ListChooser.this.hidePopup();
+
+ ListChooser.this.cacheList();
+ if (ListChooser.this.choosable == true) {
+ // If the combo box model is of sufficient length, the browser will be shown.
+ // Asking the combo box model for its size should be enough to ensure that
+ // its size is recalculated.
+ if (ListChooser.this.getModel().getSize() > ListChooser.this.longListSize) {
+ this.checkComboBoxButton();
+ ListChooser.this.browse();
+ }
+ else {
+ ListChooser.this.showPopup();
+ this.checkMousePosition();
+ }
+ }
+ if (ListChooser.this.listIsCached()) {
+ ListChooser.this.uncacheList();
+ }
+
+ ListChooser.this.popupAlreadyInProgress = false;
+ }
+
+ /** If this is not done, the button never becomes un-pressed */
+ private void checkComboBoxButton() {
+ try {
+ BasicComboBoxUI comboBoxUi = (BasicComboBoxUI) ListChooser.this.getUI();
+ JButton arrowButton = (JButton) ObjectTools.get(comboBoxUi, "arrowButton");
+ arrowButton.getModel().setPressed(false);
+ }
+ catch (Exception ex) {
+ // this is a huge hack to try and make the combo box look right,
+ // so if it doesn't work, just swallow the exception
+ this.handleException(ex);
+ }
+ }
+
+ private void handleException(@SuppressWarnings("unused") Exception ex) {
+ // do nothing for now
+ }
+
+ /**
+ * Moves the mouse back to its original position before any jiggery pokery that we've done.
+ */
+ private void checkMousePosition() {
+ if (this.eventComponent == null) {
+ return;
+ }
+
+ final Point newComponentLocation = this.eventComponent.getLocationOnScreen();
+ boolean componentMoved =
+ ((newComponentLocation.x - this.componentLocation.x) != 0)
+ || ((newComponentLocation.y - this.componentLocation.y) != 0);
+
+ if (componentMoved) {
+ try {
+ new Robot().mouseMove(
+ newComponentLocation.x + this.mouseLocation.x,
+ newComponentLocation.y + this.mouseLocation.y
+ );
+ }
+ catch (AWTException ex) {
+ // move failed - do nothing
+ }
+ }
+ }
+ }
+
+ /**
+ * This will be called when the user presses F3 or chooses
+ * 'Go To' in the context menu
+ */
+ public interface NodeSelector {
+ /**
+ * Select the appropriate Node in the tree or the editor panel.
+ */
+ void selectNodeFor(Object item);
+
+ /**
+ * This NodeSelector will do nothing when selectNodeFor(Object) is called
+ */
+ final class Default
+ implements NodeSelector, Serializable
+ {
+ public static final NodeSelector INSTANCE = new Default();
+ public static NodeSelector instance() {
+ return INSTANCE;
+ }
+ // ensure single instance
+ private Default() {
+ super();
+ }
+ @Override
+ public void selectNodeFor(Object item) {
+ //default is to do nothing
+ }
+ @Override
+ public String toString() {
+ return ObjectTools.singletonToString(this);
+ }
+ private static final long serialVersionUID = 1L;
+ private Object readResolve() {
+ // replace this object with the singleton
+ return INSTANCE;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/NonCachingComboBoxModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/NonCachingComboBoxModel.java
new file mode 100644
index 0000000..4b4469e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/NonCachingComboBoxModel.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import javax.swing.ComboBoxModel;
+import javax.swing.event.ListDataListener;
+
+/**
+ * This implementation of the CachingComboBoxModel interface can be used
+ * whenever there is no need for caching (i.e. the contents of the selection
+ * list can be generated with little latency). All the normal ComboBoxModel
+ * behavior is delegated to a client-supplied ComboBoxModel.
+ */
+public class NonCachingComboBoxModel
+ implements CachingComboBoxModel
+{
+ private ComboBoxModel wrappedComboBoxModel;
+
+
+ public NonCachingComboBoxModel(ComboBoxModel wrappedComboBoxModel) {
+ this.wrappedComboBoxModel = wrappedComboBoxModel;
+ }
+
+
+ // ********** CachingComboBoxModel implementation **********
+
+ @Override
+ public void cacheList() {
+ //do nothing
+ }
+
+ @Override
+ public void uncacheList() {
+ //do nothing
+ }
+
+ @Override
+ public boolean isCached() {
+ return false;
+ }
+
+
+ // ********** ComboBoxModel implementation **********
+
+ @Override
+ public void setSelectedItem(Object anItem) {
+ this.wrappedComboBoxModel.setSelectedItem(anItem);
+ }
+
+ @Override
+ public Object getSelectedItem() {
+ return this.wrappedComboBoxModel.getSelectedItem();
+ }
+
+
+ // ********** ListModel implementation **********
+
+ @Override
+ public int getSize() {
+ return this.wrappedComboBoxModel.getSize();
+ }
+
+ @Override
+ public Object getElementAt(int index) {
+ return this.wrappedComboBoxModel.getElementAt(index);
+ }
+
+ @Override
+ public void addListDataListener(ListDataListener l) {
+ this.wrappedComboBoxModel.addListDataListener(l);
+ }
+
+ @Override
+ public void removeListDataListener(ListDataListener l) {
+ this.wrappedComboBoxModel.removeListDataListener(l);
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListBrowser.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListBrowser.java
new file mode 100644
index 0000000..f16045f
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListBrowser.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import javax.swing.Icon;
+import javax.swing.JComboBox;
+import javax.swing.JOptionPane;
+import javax.swing.ListModel;
+
+/**
+ * This implementation of ListChooser.Browser uses a
+ * JOptionPane to prompt the user for the selection. Subclasses
+ * can change the dialog's title, message, and/or icon.
+ */
+public class SimpleListBrowser
+ implements ListChooser.ListBrowser
+{
+ /** Default constructor */
+ protected SimpleListBrowser() {
+ super();
+ }
+
+ /**
+ * Prompt the user using a JOptionPane.
+ */
+ @Override
+ public void browse(ListChooser chooser) {
+ Object selection =
+ JOptionPane.showInputDialog(
+ chooser,
+ this.message(chooser),
+ this.title(chooser),
+ this.messageType(chooser),
+ this.icon(chooser),
+ this.selectionValues(chooser),
+ this.initialSelectionValue(chooser)
+ );
+
+ if (selection != null) {
+ chooser.getModel().setSelectedItem(selection);
+ }
+ }
+
+ protected Object message(@SuppressWarnings("unused") JComboBox comboBox) {
+ return null;
+ }
+
+ protected String title(@SuppressWarnings("unused") JComboBox comboBox) {
+ return null;
+ }
+
+ protected int messageType(@SuppressWarnings("unused") JComboBox comboBox) {
+ return JOptionPane.QUESTION_MESSAGE;
+ }
+
+ protected Icon icon(@SuppressWarnings("unused") JComboBox comboBox) {
+ return null;
+ }
+
+ protected Object[] selectionValues(JComboBox comboBox) {
+ return this.convertToArray(comboBox.getModel());
+ }
+
+ protected Object initialSelectionValue(JComboBox comboBox) {
+ return comboBox.getModel().getSelectedItem();
+ }
+
+ /**
+ * Convert the list of objects in the specified list model
+ * into an array.
+ */
+ protected Object[] convertToArray(ListModel model) {
+ int size = model.getSize();
+ Object[] result = new Object[size];
+ for (int i = 0; i < size; i++) {
+ result[i] = model.getElementAt(i);
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListCellRenderer.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListCellRenderer.java
new file mode 100644
index 0000000..dfb4ca2
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListCellRenderer.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Component;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.Icon;
+import javax.swing.JList;
+import org.eclipse.persistence.tools.utility.StringTools;
+
+/**
+ * This renderer should behave the same as the DefaultListCellRenderer;
+ * but it slightly refactors the calculation of the icon and text of the list
+ * cell so that subclasses can easily override the methods that build
+ * the icon and text.
+ *
+ * In most cases, you need only override:
+ * #buildIcon(Object value)
+ * #buildText(Object value)
+ */
+public class SimpleListCellRenderer
+ extends DefaultListCellRenderer
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a simple renderer.
+ */
+ public SimpleListCellRenderer() {
+ super();
+ }
+
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ // substitute null for the cell value so nothing is drawn initially...
+ super.getListCellRendererComponent(list, null, index, isSelected, cellHasFocus);
+ this.setOpaque(true);
+
+ // ...then set the icon and text manually
+ this.setIcon(this.buildIcon(list, value, index, isSelected, cellHasFocus));
+ this.setText(this.buildText(list, value, index, isSelected, cellHasFocus));
+
+ this.setToolTipText(this.buildToolTipText(list, value, index, isSelected, cellHasFocus));
+
+ // the context will be initialized only if a reader is running
+ if (this.accessibleContext != null) {
+ this.accessibleContext.setAccessibleName(this.buildAccessibleName(list, value, index, isSelected, cellHasFocus));
+ }
+
+ return this;
+ }
+
+ /**
+ * Return the icon representation of the specified cell
+ * value and other settings. (Even more settings are
+ * accessible via inherited getters: hasFocus, isEnabled, etc.)
+ */
+ protected Icon buildIcon(@SuppressWarnings("unused") JList list, Object value, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") boolean isSelected, @SuppressWarnings("unused") boolean cellHasFocus) {
+ return this.buildIcon(value);
+ }
+
+ /**
+ * Return the icon representation of the specified cell
+ * value. The default is to display no icon at all unless the
+ * value itself is an icon.
+ */
+ protected Icon buildIcon(Object value) {
+ // replicate the default behavior
+ return (value instanceof Icon) ? (Icon) value : null;
+ }
+
+ /**
+ * Return the textual representation of the specified cell
+ * value and other settings. (Even more settings are
+ * accessible via inherited getters: hasFocus, isEnabled, etc.)
+ */
+ protected String buildText(@SuppressWarnings("unused") JList list, Object value, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") boolean isSelected, @SuppressWarnings("unused") boolean cellHasFocus) {
+ return this.buildText(value);
+ }
+
+ /**
+ * Return the textual representation of the specified cell
+ * value. The default is to display the object's default string
+ * representation (as returned by #toString()); unless the
+ * value itself is an icon, in which case no text is displayed.
+ */
+ protected String buildText(Object value) {
+ return (value instanceof Icon) ? StringTools.EMPTY_STRING : ((value == null) ? StringTools.EMPTY_STRING : value.toString());
+ }
+
+ /**
+ * Return the text displayed when the cursor lingers over the specified cell.
+ * (Even more settings are accessible via inherited getters: hasFocus, isEnabled, etc.)
+ */
+ protected String buildToolTipText(@SuppressWarnings("unused") JList list, Object value, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") boolean isSelected, @SuppressWarnings("unused") boolean cellHasFocus) {
+ return this.buildToolTipText(value);
+ }
+
+ /**
+ * Return the text displayed when the cursor lingers over the specified cell.
+ */
+ protected String buildToolTipText(@SuppressWarnings("unused") Object value) {
+ return null;
+ }
+
+ /**
+ * Return the accessible name to be given to the component used to render
+ * the given value and other settings. (Even more settings are accessible via
+ * inherited getters: hasFocus, isEnabled, etc.)
+ */
+ protected String buildAccessibleName(@SuppressWarnings("unused") JList list, Object value, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") boolean isSelected, @SuppressWarnings("unused") boolean cellHasFocus) {
+ return this.buildAccessibleName(value);
+ }
+
+ /**
+ * Return the accessible name to be given to the component used to render
+ * the given value.
+ */
+ protected String buildAccessibleName(@SuppressWarnings("unused") Object value) {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SpinnerTableCellRenderer.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SpinnerTableCellRenderer.java
new file mode 100644
index 0000000..a59b883
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SpinnerTableCellRenderer.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JSpinner;
+import javax.swing.JTable;
+import javax.swing.SpinnerModel;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * Make the cell look like a spinner.
+ */
+@SuppressWarnings("nls")
+public class SpinnerTableCellRenderer
+ implements TableCellEditorAdapter.Renderer
+{
+ /** the component used to paint the cell */
+ protected JSpinner spinner;
+
+ /** the listener to be notified on an immediate edit */
+ protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
+
+
+ // ********** constructors/initialization **********
+
+ /**
+ * Construct a cell renderer that uses the default
+ * spinner model, which is a "number" model.
+ */
+ public SpinnerTableCellRenderer() {
+ super();
+ this.initialize();
+ }
+
+ /**
+ * Construct a cell renderer that uses the specified
+ * spinner model, which will determine how the values are displayed.
+ */
+ public SpinnerTableCellRenderer(SpinnerModel model) {
+ this();
+ this.setModel(model);
+ }
+
+ protected void initialize() {
+ this.spinner = this.buildSpinner();
+ }
+
+ protected JSpinner buildSpinner() {
+ JSpinner s = new JSpinner();
+ s.addChangeListener(this.buildChangeListener());
+ return s;
+ }
+
+ private ChangeListener buildChangeListener() {
+ return new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ if (SpinnerTableCellRenderer.this.immediateEditListener != null) {
+ SpinnerTableCellRenderer.this.immediateEditListener.immediateEdit();
+ }
+ }
+ };
+ }
+
+
+ // ********** TableCellRenderer implementation **********
+
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
+ this.spinner.setComponentOrientation(table.getComponentOrientation());
+ this.spinner.setFont(table.getFont());
+ this.spinner.setEnabled(table.isEnabled());
+
+ JComponent editor = this.editor();
+ editor.setForeground(this.foregroundColor(table, value, selected, hasFocus, row, column));
+ editor.setBackground(this.backgroundColor(table, value, selected, hasFocus, row, column));
+ this.spinner.setBorder(this.border(table, value, selected, hasFocus, row, column));
+
+ this.setValue(value);
+ return this.spinner;
+ }
+
+ /**
+ * Return the cell's foreground color.
+ */
+ protected Color foregroundColor(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, int row, int column) {
+ if (selected) {
+ if (hasFocus && table.isCellEditable(row, column)) {
+ return UIManager.getColor("Table.focusCellForeground");
+ }
+ return table.getSelectionForeground();
+ }
+ return table.getForeground();
+ }
+
+ /**
+ * Return the cell's background color.
+ */
+ protected Color backgroundColor(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, int row, int column) {
+ if (selected) {
+ if (hasFocus && table.isCellEditable(row, column)) {
+ return UIManager.getColor("Table.focusCellBackground");
+ }
+ return table.getSelectionBackground();
+ }
+ return table.getBackground();
+ }
+
+ /**
+ * Return the cell's border.
+ */
+ protected Border border(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, @SuppressWarnings("unused") int row, @SuppressWarnings("unused") int column) {
+ if (hasFocus) {
+ return UIManager.getBorder("Table.focusCellHighlightBorder");
+ }
+ if (selected) {
+ return BorderFactory.createLineBorder(table.getSelectionBackground(), 1);
+ }
+ return BorderFactory.createLineBorder(table.getBackground(), 1);
+ }
+
+ /**
+ * Return the editor component whose colors should be set
+ * by the renderer.
+ */
+ protected JComponent editor() {
+ JComponent editor = this.spinner.getEditor();
+ if (editor instanceof JSpinner.DefaultEditor) {
+ // typically, the editor will be the default or one of its subclasses...
+ editor = ((JSpinner.DefaultEditor) editor).getTextField();
+ }
+ return editor;
+ }
+
+ /**
+ * Set the spinner's value
+ */
+ protected void setValue(Object value) {
+ // CR#3999318 - This null check needs to be removed once JDK bug is fixed
+ if (value == null) {
+ value = Integer.valueOf(0);
+ }
+ this.spinner.setValue(value);
+ }
+
+
+ // ********** TableCellEditorAdapter.Renderer implementation **********
+
+ @Override
+ public Object getValue() {
+ return this.spinner.getValue();
+ }
+
+ @Override
+ public void setImmediateEditListener(TableCellEditorAdapter.ImmediateEditListener listener) {
+ this.immediateEditListener = listener;
+ }
+
+
+ // ********** public API **********
+
+ /**
+ * Set the spinner's model.
+ */
+ public void setModel(SpinnerModel model) {
+ this.spinner.setModel(model);
+ }
+
+ /**
+ * Return the renderer's preferred height. This allows you
+ * to set the row height to something the spinner will look good in....
+ */
+ public int preferredHeight() {
+ // add in space for the border top and bottom
+ return (int) this.spinner.getPreferredSize().getHeight() + 2;
+ }
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/TableCellEditorAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/TableCellEditorAdapter.java
new file mode 100644
index 0000000..d691ee8
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/TableCellEditorAdapter.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Component;
+import javax.swing.AbstractCellEditor;
+import javax.swing.JTable;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+
+/**
+ * A table cell editor that wraps a table cell renderer.
+ */
+public class TableCellEditorAdapter
+ extends AbstractCellEditor
+ implements TableCellEditor
+{
+ /** delegate to a renderer */
+ private Renderer renderer;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors/initialization **********
+
+ private TableCellEditorAdapter() {
+ super();
+ }
+
+ /**
+ * Construct a cell editor that behaves like the specified renderer.
+ */
+ public TableCellEditorAdapter(Renderer renderer) {
+ this();
+ this.initialize(renderer);
+ }
+
+ protected void initialize(Renderer r) {
+ this.renderer = r;
+ r.setImmediateEditListener(this.buildImmediateEditListener());
+ }
+
+ private ImmediateEditListener buildImmediateEditListener() {
+ return new ImmediateEditListener() {
+ @Override
+ public void immediateEdit() {
+ TableCellEditorAdapter.this.stopCellEditing();
+ }
+ };
+ }
+
+
+ // ********** CellEditor implementation **********
+
+ @Override
+ public Object getCellEditorValue() {
+ return this.renderer.getValue();
+ }
+
+
+ // ********** TableCellEditor implementation **********
+
+ @Override
+ public Component getTableCellEditorComponent(JTable table, Object value, boolean selected, int row, int column) {
+ return this.renderer.getTableCellRendererComponent(table, value, selected, true, row, column);
+ }
+
+
+ // ********** Member classes **********************************************
+
+ /**
+ * This interface defines the methods that must be implemented by a renderer
+ * that can be wrapped by a TableCellEditorAdapter.
+ */
+ public interface Renderer
+ extends TableCellRenderer
+ {
+ /**
+ * Return the current value of the renderer.
+ */
+ Object getValue();
+
+ /**
+ * Set the immediate edit listener
+ */
+ void setImmediateEditListener(ImmediateEditListener listener);
+ }
+
+
+ public interface ImmediateEditListener {
+ /**
+ * Called when the renderer does an "immediate edit"
+ */
+ void immediateEdit();
+ }
+}
\ No newline at end of file