/*******************************************************************************
* Copyright (c) 1998, 2015 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 from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.test.uitools.cell;
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.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ButtonModel;
import javax.swing.ComboBoxModel;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SpinnerModel;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.text.Document;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.eclipse.persistence.tools.workbench.test.uitools.app.swing.TableModelAdapterTests.Crowd;
import org.eclipse.persistence.tools.workbench.test.uitools.app.swing.TableModelAdapterTests.Person;
import org.eclipse.persistence.tools.workbench.uitools.Displayable;
import org.eclipse.persistence.tools.workbench.uitools.app.AbstractTreeNodeValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.CollectionAspectAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.CollectionValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.ItemPropertyListValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.ListValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.NullListValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.PropertyAspectAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.PropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SimpleCollectionValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SimpleListValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SimplePropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SortedListValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.TransformationListValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.TransformationPropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.TreeNodeValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.ValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.CheckBoxModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.ComboBoxModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.DateSpinnerModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.DocumentAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.NumberSpinnerModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.TreeModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.cell.CheckBoxTreeCellEditor;
import org.eclipse.persistence.tools.workbench.uitools.cell.CheckBoxTreeCellRenderer;
import org.eclipse.persistence.tools.workbench.uitools.cell.ComboBoxTreeCellEditor;
import org.eclipse.persistence.tools.workbench.uitools.cell.ComboBoxTreeCellRenderer;
import org.eclipse.persistence.tools.workbench.uitools.cell.EditingNode;
import org.eclipse.persistence.tools.workbench.uitools.cell.NodeTreeCellEditor;
import org.eclipse.persistence.tools.workbench.uitools.cell.NodeTreeCellRenderer;
import org.eclipse.persistence.tools.workbench.uitools.cell.NullTreeCellEditor;
import org.eclipse.persistence.tools.workbench.uitools.cell.SimpleTreeCellRenderer;
import org.eclipse.persistence.tools.workbench.uitools.cell.SpinnerTreeCellEditor;
import org.eclipse.persistence.tools.workbench.uitools.cell.SpinnerTreeCellRenderer;
import org.eclipse.persistence.tools.workbench.uitools.cell.TextFieldTreeCellEditor;
import org.eclipse.persistence.tools.workbench.uitools.cell.TextFieldTreeCellRenderer;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
import org.eclipse.persistence.tools.workbench.utility.events.CollectionChangeEvent;
import org.eclipse.persistence.tools.workbench.utility.events.CollectionChangeListener;
/**
* an example UI for testing various tree cell editors
*/
public class TreeCellEditorUITest {
CollectionValueModel eyeColorListHolder;
private PropertyValueModel crowdHolder;
private PropertyValueModel selectedPersonHolder;
private TreeModel treeModel;
private TreeSelectionModel treeSelectionModel;
private Map renderers;
private Map editors;
// hold these actions so we can enable/disable them
private Action removeAction;
private Action renameAction;
public static void main(String[] args) throws Exception {
new TreeCellEditorUITest().exec(args);
}
protected TreeCellEditorUITest() {
super();
}
protected void exec(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
this.eyeColorListHolder = this. buildEyeColorCollectionHolder();
this.crowdHolder = this.buildCrowdHolder();
this.selectedPersonHolder = this.buildSelectedPersonHolder();
this.treeModel = this.buildTreeModel();
this.treeSelectionModel = this.buildTreeSelectionModel();
this.renderers = new HashMap();
this.editors = new HashMap();
this.openWindow();
}
private CollectionValueModel buildEyeColorCollectionHolder() {
return new SimpleCollectionValueModel(Person.getValidEyeColors());
}
private PropertyValueModel buildCrowdHolder() {
return new SimplePropertyValueModel(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 PropertyValueModel buildSelectedPersonHolder() {
return new SimplePropertyValueModel();
}
private TreeModel buildTreeModel() {
return new TreeModelAdapter(this.buildCrowdNodeAdapter());
}
private PropertyValueModel buildCrowdNodeAdapter() {
return new TransformationPropertyValueModel(this.crowdHolder) {
protected Object transform(Object value) {
return new CrowdNode((Crowd) value);
}
};
}
private TreeSelectionModel buildTreeSelectionModel() {
TreeSelectionModel tsm = new DefaultTreeSelectionModel();
tsm.setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
// tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tsm.addTreeSelectionListener(this.buildTreeSelectionListener());
return tsm;
}
private TreeSelectionListener buildTreeSelectionListener() {
return new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
TreeCellEditorUITest.this.treeSelectionChanged(e);
}
};
}
void treeSelectionChanged(TreeSelectionEvent e) {
Person selection = this.selectedPerson();
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().getName());
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() {
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() {
JTree tree = new JTree(this.treeModel);
tree.setSelectionModel(this.treeSelectionModel);
tree.setCellRenderer(new NodeTreeCellRenderer());
tree.setCellEditor(new NodeTreeCellEditor());
tree.setEditable(this.isEditable());
tree.setRootVisible(true);
tree.setShowsRootHandles(true);
tree.setDoubleBuffered(true);
// comment out this line to try variable row height (which doesn't look so good...)
tree.setRowHeight(26);
return tree;
}
protected boolean isEditable() {
return true;
}
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") {
public void actionPerformed(ActionEvent event) {
TreeCellEditorUITest.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") {
public void actionPerformed(ActionEvent event) {
TreeCellEditorUITest.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") {
public void actionPerformed(ActionEvent event) {
TreeCellEditorUITest.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") {
public void actionPerformed(ActionEvent event) {
TreeCellEditorUITest.this.addEyeColor();
}
};
action.setEnabled(true);
return action;
}
void addEyeColor() {
String color = this.promptUserForEyeColor();
if (color != null) {
this.eyeColorListHolder.addItem(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 (CollectionTools.contains((Iterator) this.eyeColorListHolder.getValue(), 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") {
public void actionPerformed(ActionEvent event) {
TreeCellEditorUITest.this.printCrowd();
}
};
action.setEnabled(true);
return action;
}
void printCrowd() {
System.out.println(this.crowd());
for (Iterator 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") {
public void actionPerformed(ActionEvent event) {
TreeCellEditorUITest.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(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 (CollectionTools.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 PropertyValueModel buildNameAdapter() {
return new PropertyAspectAdapter(this.selectedPersonHolder, Person.NAME_PROPERTY) {
protected Object getValueFromSubject() {
return ((Person) this.subject).getName();
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setName((String) value);
}
};
}
// ********** birth date spinner **********
private JSpinner buildBirthDateSpinner() {
return new JSpinner(this.buildBirthDateSpinnerModel());
}
private SpinnerModel buildBirthDateSpinnerModel() {
return new DateSpinnerModelAdapter(this.buildBirthDateAdapter());
}
private PropertyValueModel buildBirthDateAdapter() {
return new PropertyAspectAdapter(this.selectedPersonHolder, Person.BIRTH_DATE_PROPERTY) {
protected Object getValueFromSubject() {
return ((Person) this.subject).getBirthDate();
}
protected void setValueOnSubject(Object value) {
((Person) 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 PropertyValueModel buildGoneWestDateAdapter() {
return new PropertyAspectAdapter(this.selectedPersonHolder, Person.GONE_WEST_DATE_PROPERTY) {
protected Object getValueFromSubject() {
return ((Person) this.subject).getGoneWestDate();
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setGoneWestDate((Date) value);
}
};
}
// ********** eye color combo-box **********
private JComboBox buildEyeColorComboBox() {
return new JComboBox(this.buildEyeColorComboBoxModel());
}
private ComboBoxModel buildEyeColorComboBoxModel() {
return new ComboBoxModelAdapter(this.eyeColorListHolder, this.buildEyeColorAdapter());
}
private PropertyValueModel buildEyeColorAdapter() {
return new PropertyAspectAdapter(this.selectedPersonHolder, Person.EYE_COLOR_PROPERTY) {
protected Object getValueFromSubject() {
return ((Person) this.subject).getEyeColor();
}
protected void setValueOnSubject(Object value) {
((Person) 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 PropertyValueModel buildEvilAdapter() {
return new PropertyAspectAdapter(this.selectedPersonHolder, Person.EVIL_PROPERTY) {
protected Object getValueFromSubject() {
return Boolean.valueOf(((Person) this.subject).isEvil());
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setEvil(((Boolean) value).booleanValue());
}
};
}
// ********** rank spinner **********
private JSpinner buildRankSpinner() {
return new JSpinner(this.buildRankSpinnerModel());
}
private SpinnerModel buildRankSpinnerModel() {
return new NumberSpinnerModelAdapter(this.buildRankAdapter());
}
private PropertyValueModel buildRankAdapter() {
return new PropertyAspectAdapter(this.selectedPersonHolder, Person.RANK_PROPERTY) {
protected Object getValueFromSubject() {
return new Integer(((Person) this.subject).getRank());
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setRank(((Integer) value).intValue());
}
};
}
// ********** adventure count spinner **********
private JSpinner buildAdventureCountSpinner() {
return new JSpinner(this.buildAdventureCountSpinnerModel());
}
private SpinnerModel buildAdventureCountSpinnerModel() {
return new NumberSpinnerModelAdapter(this.buildAdventureCountAdapter());
}
private PropertyValueModel buildAdventureCountAdapter() {
return new PropertyAspectAdapter(this.selectedPersonHolder, Person.ADVENTURE_COUNT_PROPERTY) {
protected Object getValueFromSubject() {
return new Integer(((Person) this.subject).getAdventureCount());
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setAdventureCount(((Integer) value).intValue());
}
};
}
// ********** renderer/editor caches **********
void putRenderer(Object key, TreeCellRenderer renderer) {
this.renderers.put(key, renderer);
}
TreeCellRenderer getRenderer(Object key) {
return (TreeCellRenderer) this.renderers.get(key);
}
void putEditor(Object key, TreeCellEditor editor) {
this.editors.put(key, editor);
}
TreeCellEditor getEditor(Object key) {
return (TreeCellEditor) this.editors.get(key);
}
// ********** queries **********
private Crowd crowd() {
return (Crowd) this.crowdHolder.getValue();
}
private CrowdNode crowdNode() {
return (CrowdNode) this.treeModel.getRoot();
}
private LocalNode selectedNode() {
if (this.treeSelectionModel.isSelectionEmpty()) {
return null;
}
return (LocalNode) this.treeSelectionModel.getSelectionPath().getLastPathComponent();
}
private Person selectedPerson() {
if (this.treeSelectionModel.isSelectionEmpty()) {
return null;
}
return this.selectedNode().getPerson();
}
// ********** behavior **********
private void setSelectedPerson(Person person) {
this.setSelectedPersonNode(this.crowdNode().personNodeFor(person));
}
private void setSelectedPersonNode(PersonNode personNode) {
this.treeSelectionModel.setSelectionPath(new TreePath(personNode.path()));
}
// ********** nodes **********
/**
* interface defining protocol required by all nodes used in
* the tree
*/
interface LocalNode extends EditingNode {
/**
* return the person associated with the node:
* - a crowd node will return null
* - a person node will return its person
* - an attribute node will return its parent's person
*/
Person getPerson();
}
class CrowdNode extends AbstractTreeNodeValueModel implements LocalNode {
private Crowd crowd;
private ListValueModel childrenModel;
private CollectionChangeListener crowdListener;
// ********** construction/initialization **********
public CrowdNode(Crowd crowd) {
super();
this.crowd = crowd;
this.childrenModel = this.buildChildrenModel(crowd);
}
protected void initialize() {
super.initialize();
this.crowdListener = this.buildCrowdListener();
}
private CollectionChangeListener buildCrowdListener() {
return new CollectionChangeListener() {
public void collectionChanged(CollectionChangeEvent e) {
CrowdNode.this.crowdChanged();
}
public void itemsAdded(CollectionChangeEvent e) {
CrowdNode.this.crowdChanged();
}
public void itemsRemoved(CollectionChangeEvent e) {
CrowdNode.this.crowdChanged();
}
};
}
void crowdChanged() {
this.fireStateChanged();
}
// the list should be sorted
protected ListValueModel buildChildrenModel(Crowd c) {
return new SortedListValueModelAdapter(this.buildDisplayStringAdapter(c));
}
// the display string (name) of each person node can change
protected ListValueModel buildDisplayStringAdapter(Crowd c) {
return new ItemPropertyListValueModelAdapter(this.buildPersonNodeAdapter(c), Displayable.DISPLAY_STRING_PROPERTY);
}
// wrap the persons in the list in person nodes
protected ListValueModel buildPersonNodeAdapter(Crowd c) {
return new TransformationListValueModelAdapter(this.buildPeopleAdapter(c)) {
protected Object transformItem(Object item) {
return CrowdNode.this.buildPersonNode((Person) item);
}
};
}
protected PersonNode buildPersonNode(Person person) {
return new PersonNode(this, person);
}
// the list of children can change
protected CollectionValueModel buildPeopleAdapter(Crowd c) {
return new CollectionAspectAdapter(Crowd.PEOPLE_COLLECTION, c) {
protected Iterator getValueFromSubject() {
return ((Crowd) this.subject).people();
}
protected int sizeFromSubject() {
return ((Crowd) this.subject).peopleSize();
}
};
}
// ********** LocalNode implementation **********
public Person getPerson() {
return null;
}
public Object getCellValue() {
return this.crowd;
}
public TreeCellRenderer getRenderer() {
TreeCellRenderer renderer = TreeCellEditorUITest.this.getRenderer(this.getClass());
if (renderer == null) {
renderer = this.buildRenderer();
TreeCellEditorUITest.this.putRenderer(this.getClass(), renderer);
}
return renderer;
}
private TreeCellRenderer buildRenderer() {
return new SimpleTreeCellRenderer() {
protected String buildText(Object value) {
return "Crowd of " + ((Crowd) value).peopleSize() + " person(s)";
}
};
}
public TreeCellEditor getEditor() {
return NullTreeCellEditor.instance();
}
// ********** TreeNodeValueModel implementation **********
public Object getValue() {
return this.crowd;
}
public void setValue(Object value) {
Object old = this.crowd;
this.crowd = (Crowd) value;
this.firePropertyChanged(VALUE, old, value);
}
public TreeNodeValueModel getParent() {
return null;
}
public ListValueModel getChildrenModel() {
return this.childrenModel;
}
// ********** AbstractTreeNodeValueModel implementation **********
protected void engageValue() {
this.crowd.addCollectionChangeListener(Crowd.PEOPLE_COLLECTION, this.crowdListener);
}
protected void disengageValue() {
this.crowd.removeCollectionChangeListener(Crowd.PEOPLE_COLLECTION, this.crowdListener);
}
// ********** queries **********
public PersonNode personNodeFor(Person person) {
for (Iterator stream = (Iterator) this.childrenModel.getValue(); stream.hasNext(); ) {
PersonNode pNode = (PersonNode) stream.next();
if (pNode.getValue() == person) {
return pNode;
}
}
return null;
}
// ********** standard methods **********
public String toString() {
return "Crowd(" + this.crowd.peopleSize() + " people)";
}
}
class PersonNode extends AbstractTreeNodeValueModel implements LocalNode, Displayable {
private Person person;
private CrowdNode crowdNode; // parent node
private ListValueModel childrenModel;
private PropertyChangeListener personListener;
// ********** construction/initialization **********
public PersonNode(CrowdNode crowdNode, Person person) {
super();
this.crowdNode = crowdNode;
this.person = person;
this.childrenModel = this.buildChildrenModel();
}
protected void initialize() {
super.initialize();
this.personListener = this.buildPersonListener();
}
private PropertyChangeListener buildPersonListener() {
return new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
PersonNode.this.personChanged(e);
}
};
}
protected ListValueModel buildChildrenModel() {
Object[] children = new Object[6];
children[0] = new BirthDateNode(this);
children[1] = new GoneWestDateNode(this);
children[2] = new EyeColorNode(this);
children[3] = new EvilNode(this);
children[4] = new RankNode(this);
children[5] = new AdventureCountNode(this);
return new SimpleListValueModel(Arrays.asList(children));
}
// ********** LocalNode implementation **********
public Person getPerson() {
return this.person;
}
public Object getCellValue() {
return this.person;
}
public TreeCellRenderer getRenderer() {
TreeCellRenderer renderer = TreeCellEditorUITest.this.getRenderer(this.getClass());
if (renderer == null) {
renderer = this.buildRenderer();
TreeCellEditorUITest.this.putRenderer(this.getClass(), renderer);
}
return renderer;
}
private TreeCellRenderer buildRenderer() {
return new SimpleTreeCellRenderer() {
protected String buildText(Object value) {
return ((Person) value).getName();
}
};
}
public TreeCellEditor getEditor() {
return NullTreeCellEditor.instance();
}
// ********** TreeNodeValueModel implementation **********
public Object getValue() {
return this.person;
}
public void setValue(Object value) {
Object old = this.person;
this.person = (Person) value;
this.firePropertyChanged(VALUE, old, value);
}
public TreeNodeValueModel getParent() {
return this.crowdNode;
}
public ListValueModel getChildrenModel() {
return this.childrenModel;
}
// ********** AbstractTreeNodeValueModel implementation **********
protected void engageValue() {
this.person.addPropertyChangeListener(Person.NAME_PROPERTY, this.personListener);
}
protected void disengageValue() {
this.person.removePropertyChangeListener(Person.NAME_PROPERTY, this.personListener);
}
// ********** Displayable implementation **********
public String displayString() {
return this.person.getName();
}
public Icon icon() {
return null;
}
// ********** behavior **********
protected void personChanged(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());
}
// ********** standard methods **********
// use the standard Displayable comparator
public int compareTo(Object o) {
return DEFAULT_COMPARATOR.compare(this, o);
}
public String toString() {
return "PersonNode(" + this.person + ")";
}
}
abstract class PersonAttributeNode extends AbstractTreeNodeValueModel implements LocalNode {
private PropertyValueModel attributeAdapter;
private PersonNode personNode; // parent node
private PropertyChangeListener attributeListener;
// ********** construction/initialization **********
public PersonAttributeNode(PersonNode personNode) {
super();
this.initialize(personNode);
}
protected void initialize() {
super.initialize();
this.attributeListener = this.buildAttributeListener();
}
protected PropertyChangeListener buildAttributeListener() {
return new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
PersonAttributeNode.this.attributeChanged(e);
}
};
}
protected void initialize(PersonNode node) {
this.personNode = node;
this.attributeAdapter = this.buildAttributeAdapter();
}
protected abstract PropertyValueModel buildAttributeAdapter();
// ********** LocalNode implementation **********
public Person getPerson() {
return this.personNode.getPerson();
}
public Object getCellValue() {
return this.getValue();
}
public TreeCellRenderer getRenderer() {
TreeCellRenderer renderer = TreeCellEditorUITest.this.getRenderer(this.getClass());
if (renderer == null) {
renderer = this.buildRenderer();
TreeCellEditorUITest.this.putRenderer(this.getClass(), renderer);
}
return renderer;
}
protected abstract TreeCellRenderer buildRenderer();
public TreeCellEditor getEditor() {
TreeCellEditor editor = TreeCellEditorUITest.this.getEditor(this.getClass());
if (editor == null) {
editor = this.buildEditor();
// editor.addCellEditorListener(TreeCellEditorUITest.this.getEditor());
TreeCellEditorUITest.this.putEditor(this.getClass(), editor);
}
return editor;
}
protected TreeCellEditor buildEditor() {
return NullTreeCellEditor.instance();
}
// ********** TreeNodeValueModel implementation **********
public Object getValue() {
return this.attributeAdapter.getValue();
}
public void setValue(Object value) {
this.attributeAdapter.setValue(value);
}
public TreeNodeValueModel getParent() {
return this.personNode;
}
public ListValueModel getChildrenModel() {
return NullListValueModel.instance();
}
// ********** AbstractTreeNodeValueModel implementation **********
protected void engageValue() {
this.attributeAdapter.addPropertyChangeListener(ValueModel.VALUE, this.attributeListener);
}
protected void disengageValue() {
this.attributeAdapter.removePropertyChangeListener(ValueModel.VALUE, this.attributeListener);
}
// ********** behavior **********
protected void attributeChanged(PropertyChangeEvent e) {
// we need to notify listeners that our "value" has changed
this.firePropertyChanged(VALUE, e.getOldValue(), e.getNewValue());
}
}
class BirthDateNode extends PersonAttributeNode {
// ********** construction/initialization **********
public BirthDateNode(PersonNode personNode) {
super(personNode);
}
protected PropertyValueModel buildAttributeAdapter() {
return new PropertyAspectAdapter(Person.BIRTH_DATE_PROPERTY, this.getPerson()) {
protected Object getValueFromSubject() {
return ((Person) this.subject).getBirthDate();
}
protected void setValueOnSubject(Object value) {
try {
Date date = DateFormat.getDateInstance(DateFormat.SHORT).parse((String) value);
((Person) this.subject).setBirthDate(date);
} catch (ParseException ex) {
ex.printStackTrace();
// simply don't set the date if we get an exception
}
}
};
}
// ********** LocalNode implementation **********
protected TreeCellRenderer buildRenderer() {
return new TextFieldTreeCellRenderer("Birth:");
}
public TreeCellEditor buildEditor() {
// build a new renderer - do not re-use the original
return new TextFieldTreeCellEditor((TextFieldTreeCellRenderer) this.buildRenderer());
}
// ********** standard methods **********
public String toString() {
return "BirthDateNode(" + this.getValue() + ")";
}
}
class GoneWestDateNode extends PersonAttributeNode {
// ********** construction/initialization **********
public GoneWestDateNode(PersonNode personNode) {
super(personNode);
}
protected PropertyValueModel buildAttributeAdapter() {
return new PropertyAspectAdapter(Person.GONE_WEST_DATE_PROPERTY, this.getPerson()) {
protected Object getValueFromSubject() {
return ((Person) this.subject).getGoneWestDate();
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setGoneWestDate((Date) value);
}
};
}
// ********** LocalNode implementation **********
protected TreeCellRenderer buildRenderer() {
return new SpinnerTreeCellRenderer("Gone West:", this.buildRendererModel());
}
protected SpinnerModel buildRendererModel() {
return new DateSpinnerModelAdapter(new SimplePropertyValueModel());
}
public TreeCellEditor buildEditor() {
// build a new renderer - do not re-use the original
return new SpinnerTreeCellEditor((SpinnerTreeCellRenderer) this.buildRenderer());
}
// ********** standard methods **********
public String toString() {
return "GoneWestDateNode(" + this.getValue() + ")";
}
}
class EyeColorNode extends PersonAttributeNode {
// ********** construction/initialization **********
public EyeColorNode(PersonNode personNode) {
super(personNode);
}
protected PropertyValueModel buildAttributeAdapter() {
return new PropertyAspectAdapter(Person.EYE_COLOR_PROPERTY, this.getPerson()) {
protected Object getValueFromSubject() {
return ((Person) this.subject).getEyeColor();
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setEyeColor((String) value);
}
};
}
// ********** LocalNode implementation **********
protected TreeCellRenderer buildRenderer() {
return new ComboBoxTreeCellRenderer(this.buildComboBoxModel(), "Eyes:");
}
private ComboBoxModel buildComboBoxModel() {
return new ComboBoxModelAdapter(TreeCellEditorUITest.this.eyeColorListHolder, new SimplePropertyValueModel());
}
public TreeCellEditor buildEditor() {
// build a new renderer - do not re-use the original
return new ComboBoxTreeCellEditor((ComboBoxTreeCellRenderer) this.buildRenderer());
}
// ********** standard methods **********
public String toString() {
return "EyeColorNode(" + this.getValue() + ")";
}
}
class EvilNode extends PersonAttributeNode {
// ********** construction/initialization **********
public EvilNode(PersonNode personNode) {
super(personNode);
}
protected PropertyValueModel buildAttributeAdapter() {
return new PropertyAspectAdapter(Person.EVIL_PROPERTY, this.getPerson()) {
protected Object getValueFromSubject() {
return Boolean.valueOf(((Person) this.subject).isEvil());
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setEvil(((Boolean) value).booleanValue());
}
};
}
// ********** LocalNode implementation **********
protected TreeCellRenderer buildRenderer() {
return new CheckBoxTreeCellRenderer("Evil");
}
public TreeCellEditor buildEditor() {
// build a new renderer - do not re-use the original
return new CheckBoxTreeCellEditor((CheckBoxTreeCellRenderer) this.buildRenderer());
}
// ********** standard methods **********
public String toString() {
return "EvilNode(" + this.getValue() + ")";
}
}
class RankNode extends PersonAttributeNode {
// ********** construction/initialization **********
public RankNode(PersonNode personNode) {
super(personNode);
}
protected PropertyValueModel buildAttributeAdapter() {
return new PropertyAspectAdapter(Person.RANK_PROPERTY, this.getPerson()) {
protected Object getValueFromSubject() {
return new Integer(((Person) this.subject).getRank());
}
protected void setValueOnSubject(Object value) {
try {
int rank = Integer.parseInt((String) value);
((Person) this.subject).setRank(rank);
} catch (NumberFormatException ex) {
ex.printStackTrace();
// simply don't set the rank if we get an exception
}
}
};
}
// ********** LocalNode implementation **********
protected TreeCellRenderer buildRenderer() {
return new TextFieldTreeCellRenderer("Rank:");
}
public TreeCellEditor buildEditor() {
// build a new renderer - do not re-use the original
return new TextFieldTreeCellEditor((TextFieldTreeCellRenderer) this.buildRenderer());
}
// ********** standard methods **********
public String toString() {
return "RankNode(" + this.getValue() + ")";
}
}
class AdventureCountNode extends PersonAttributeNode {
// ********** construction/initialization **********
public AdventureCountNode(PersonNode personNode) {
super(personNode);
}
protected PropertyValueModel buildAttributeAdapter() {
return new PropertyAspectAdapter(Person.ADVENTURE_COUNT_PROPERTY, this.getPerson()) {
protected Object getValueFromSubject() {
return new Integer(((Person) this.subject).getAdventureCount());
}
protected void setValueOnSubject(Object value) {
((Person) this.subject).setAdventureCount(((Integer) value).intValue());
}
};
}
// ********** LocalNode implementation **********
protected TreeCellRenderer buildRenderer() {
return new SpinnerTreeCellRenderer("Adventures:");
}
public TreeCellEditor buildEditor() {
// build a new renderer - do not re-use the original
return new SpinnerTreeCellEditor((SpinnerTreeCellRenderer) this.buildRenderer());
}
// ********** standard methods **********
public String toString() {
return "AdventureCountNode(" + this.getValue() + ")";
}
}
}