blob: 07a614cb440f4b6c2a7a21538495f711cb6b63bf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2010 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.utility.tests.internal.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.jpt.common.utility.internal.CollectionTools;
import org.eclipse.jpt.common.utility.internal.model.value.CollectionAspectAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.ItemPropertyListValueModelAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.PropertyAspectAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SortedListValueModelWrapper;
import org.eclipse.jpt.common.utility.internal.model.value.swing.CheckBoxModelAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.swing.ColumnAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.swing.ComboBoxModelAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.swing.DateSpinnerModelAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.swing.DocumentAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.swing.ListModelAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.swing.NumberSpinnerModelAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.swing.ObjectListSelectionModel;
import org.eclipse.jpt.common.utility.internal.model.value.swing.TableModelAdapter;
import org.eclipse.jpt.common.utility.internal.swing.CheckBoxTableCellRenderer;
import org.eclipse.jpt.common.utility.internal.swing.ComboBoxTableCellRenderer;
import org.eclipse.jpt.common.utility.internal.swing.SpinnerTableCellRenderer;
import org.eclipse.jpt.common.utility.internal.swing.TableCellEditorAdapter;
import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
import org.eclipse.jpt.common.utility.model.value.ListValueModel;
import org.eclipse.jpt.common.utility.model.value.WritablePropertyValueModel;
import org.eclipse.jpt.common.utility.tests.internal.model.value.swing.TableModelAdapterTests.Crowd;
import org.eclipse.jpt.common.utility.tests.internal.model.value.swing.TableModelAdapterTests.Person;
import org.eclipse.jpt.common.utility.tests.internal.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 WritablePropertyValueModel<Crowd> crowdHolder;
private WritablePropertyValueModel<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 WritablePropertyValueModel<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 WritablePropertyValueModel<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 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() {
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") {
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") {
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") {
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") {
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 (CollectionTools.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") {
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") {
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 (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 WritablePropertyValueModel<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 WritablePropertyValueModel<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 WritablePropertyValueModel<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 WritablePropertyValueModel<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 WritablePropertyValueModel<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 WritablePropertyValueModel<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 WritablePropertyValueModel<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);
}
}
}