Finish implementation of ObjectArrayEditor

This commit is contained in:
Fabian Becker 2015-12-17 15:52:41 +01:00
parent 2242367832
commit ef6033c303
5 changed files with 295 additions and 57 deletions

View File

@ -3,12 +3,17 @@ package eva2.gui;
import eva2.gui.editor.*; import eva2.gui.editor.*;
import eva2.optimization.individuals.codings.gp.GPArea; import eva2.optimization.individuals.codings.gp.GPArea;
import eva2.optimization.operator.terminators.InterfaceTerminator; import eva2.optimization.operator.terminators.InterfaceTerminator;
import eva2.tools.Primitives;
import eva2.tools.SelectedTag; import eva2.tools.SelectedTag;
import eva2.tools.StringSelection; import eva2.tools.StringSelection;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor; import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager; import java.beans.PropertyEditorManager;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class PropertyEditorProvider { public class PropertyEditorProvider {
// if true, we use the GenericObjectEditor whenever no specific one is registered, so keep it true // if true, we use the GenericObjectEditor whenever no specific one is registered, so keep it true
@ -23,13 +28,24 @@ public class PropertyEditorProvider {
public static PropertyEditor findEditor(Class<?> cls) { public static PropertyEditor findEditor(Class<?> cls) {
PropertyEditor editor = PropertyEditorManager.findEditor(cls); PropertyEditor editor = PropertyEditorManager.findEditor(cls);
// Try to unwrap primitives
if (editor == null && Primitives.isWrapperType(cls)) {
editor = PropertyEditorManager.findEditor(Primitives.unwrap(cls));
}
if ((editor == null) && useDefaultGOE) { if ((editor == null) && useDefaultGOE) {
if (cls.isArray()) { if (cls.isArray()) {
editor = new ArrayEditor(); Class<?> unwrapped = Primitives.isWrapperType(cls.getComponentType()) ? Primitives.unwrap(cls.getComponentType()) : cls;
if (unwrapped.isPrimitive()) {
editor = new ArrayEditor();
} else {
editor = new ObjectArrayEditor<>(unwrapped.getComponentType());
}
} else if (cls.isEnum()) { } else if (cls.isEnum()) {
editor = new EnumEditor(); editor = new EnumEditor();
} else { } else {
editor = new GenericObjectEditor(); editor = new GenericObjectEditor();
((GenericObjectEditor)editor).setClassType(cls);
} }
} }
return editor; return editor;
@ -42,6 +58,7 @@ public class PropertyEditorProvider {
* @return * @return
*/ */
public static PropertyEditor findEditor(PropertyDescriptor prop, Object value) { public static PropertyEditor findEditor(PropertyDescriptor prop, Object value) {
PropertyEditor editor = null; PropertyEditor editor = null;
Class pec = prop.getPropertyEditorClass(); Class pec = prop.getPropertyEditorClass();
Class type = prop.getPropertyType(); Class type = prop.getPropertyType();
@ -56,10 +73,9 @@ public class PropertyEditorProvider {
if (editor == null) { if (editor == null) {
if (value != null) { if (value != null) {
// Try to unwrap primitives
// ToDo: This should be handled by the registerEditor below. findEditor however always returns the sun.beans.editor stuff. if (Primitives.isWrapperType(value.getClass())) {
if (value instanceof Enum) { editor = PropertyEditorManager.findEditor(Primitives.unwrap(value.getClass()));
editor = new EnumEditor();
} else { } else {
editor = PropertyEditorManager.findEditor(value.getClass()); editor = PropertyEditorManager.findEditor(value.getClass());
} }
@ -84,11 +100,17 @@ public class PropertyEditorProvider {
if ((editor == null) && useDefaultGOE) { if ((editor == null) && useDefaultGOE) {
if (type.isArray()) { if (type.isArray()) {
editor = new ArrayEditor(); Class<?> unwrapped = Primitives.isWrapperType(type.getComponentType()) ? Primitives.unwrap(type.getComponentType()) : type;
if (unwrapped.isPrimitive()) {
editor = new ArrayEditor();
} else {
editor = new ObjectArrayEditor<>(unwrapped.getComponentType());
}
} else if (type.isEnum()) { } else if (type.isEnum()) {
editor = new EnumEditor(); editor = new EnumEditor();
} else { } else {
editor = new GenericObjectEditor(); editor = new GenericObjectEditor();
((GenericObjectEditor)editor).setClassType(type);
} }
} }
} }
@ -116,6 +138,8 @@ public class PropertyEditorProvider {
PropertyEditorManager.registerEditor(Enum.class, EnumEditor.class); PropertyEditorManager.registerEditor(Enum.class, EnumEditor.class);
PropertyEditorManager.registerEditor(int[].class, ArrayEditor.class); PropertyEditorManager.registerEditor(int[].class, ArrayEditor.class);
PropertyEditorManager.registerEditor(double[].class, ArrayEditor.class); PropertyEditorManager.registerEditor(double[].class, ArrayEditor.class);
PropertyEditorManager.registerEditor(String[].class, ArrayEditor.class);
PropertyEditorManager.registerEditor(InterfaceTerminator[].class, ArrayEditor.class); PropertyEditorManager.registerEditor(InterfaceTerminator[].class, ArrayEditor.class);

View File

@ -227,7 +227,7 @@ public final class PropertySheetPanel extends JPanel implements PropertyChangeLi
gbConstraints.fill = GridBagConstraints.HORIZONTAL; gbConstraints.fill = GridBagConstraints.HORIZONTAL;
gbConstraints.anchor = GridBagConstraints.PAGE_START; gbConstraints.anchor = GridBagConstraints.PAGE_START;
add(buildTitledSeperator("Info"), gbConstraints); add(new TitledSeparator("Info"), gbConstraints);
gbConstraints.gridy = 1; gbConstraints.gridy = 1;
add(infoPanel, gbConstraints); add(infoPanel, gbConstraints);
@ -307,9 +307,7 @@ public final class PropertySheetPanel extends JPanel implements PropertyChangeLi
gbConstraints.gridy = 2; gbConstraints.gridy = 2;
add(new TitledSeparator("Properties"), gbConstraints);
add(buildTitledSeperator("Properties"), gbConstraints);
JScrollPane scrollableTable = new JScrollPane(propertyTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); JScrollPane scrollableTable = new JScrollPane(propertyTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
gbConstraints.gridx = 0; gbConstraints.gridx = 0;
@ -320,6 +318,8 @@ public final class PropertySheetPanel extends JPanel implements PropertyChangeLi
scrollableTable.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); scrollableTable.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
add(scrollableTable, gbConstraints); add(scrollableTable, gbConstraints);
setMinimumSize(new Dimension(350, 0));
validate(); validate();
setVisible(true); setVisible(true);
} }
@ -333,24 +333,6 @@ public final class PropertySheetPanel extends JPanel implements PropertyChangeLi
return label; return label;
} }
private static JPanel buildTitledSeperator(String title) {
JPanel titledSeperator = new JPanel(new GridBagLayout());
GridBagConstraints gbConstraints = new GridBagConstraints();
gbConstraints.gridx = 0;
gbConstraints.gridy = 0;
titledSeperator.add(new JLabel("<html><b>" + title), gbConstraints);
gbConstraints.gridx = 1;
gbConstraints.gridy = 0;
gbConstraints.weightx = 1.0;
gbConstraints.fill = GridBagConstraints.HORIZONTAL;
titledSeperator.add(new JSeparator(JSeparator.HORIZONTAL), gbConstraints);
return titledSeperator;
}
public static PropertyDescriptor[] getProperties(Object target) { public static PropertyDescriptor[] getProperties(Object target) {
BeanInfo bi; BeanInfo bi;
try { try {

View File

@ -79,7 +79,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
boolean consistentView = true; // be optimistic... boolean consistentView;
if (view instanceof PropertyText) { // check consistency! if (view instanceof PropertyText) { // check consistency!
consistentView = ((PropertyText) view).checkConsistency(); consistentView = ((PropertyText) view).checkConsistency();
if (!consistentView) { if (!consistentView) {
@ -238,7 +238,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
list.ensureIndexIsVisible(index); list.ensureIndexIsVisible(index);
propPanel.getEditor().setValue(item); propPanel.getEditor().setValue(item);
propPanel.showDialog(); propPanel.showDialog();
propPanel = null;
} }
} }
} }
@ -401,7 +401,6 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
} }
} }
//setPreferredSize(new Dimension(400,500));
if (withAddButton && !(upperButtonList.contains(addButton))) { if (withAddButton && !(upperButtonList.contains(addButton))) {
upperButtonList.add(addButton); upperButtonList.add(addButton);
@ -415,9 +414,6 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
// Upper Button Panel // Upper Button Panel
JPanel combiUpperPanel = new JPanel(getButtonLayout(0, upperButtonList)); JPanel combiUpperPanel = new JPanel(getButtonLayout(0, upperButtonList));
// ToDo Figure out how to now show this on Job Pane
combiUpperPanel.add(view);
view.setVisible(withAddButton);
for (JButton but : upperButtonList) { for (JButton but : upperButtonList) {
combiUpperPanel.add(but); combiUpperPanel.add(but);
@ -431,6 +427,12 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
gbConstraints.gridy = 0; gbConstraints.gridy = 0;
add(combiUpperPanel, gbConstraints); add(combiUpperPanel, gbConstraints);
gbConstraints.gridy++;
gbConstraints.fill = GridBagConstraints.HORIZONTAL;
gbConstraints.weightx = 1.0;
add(view, gbConstraints);
view.setVisible(withAddButton);
// Job List // Job List
gbConstraints.gridy++; gbConstraints.gridy++;
gbConstraints.fill = GridBagConstraints.BOTH; gbConstraints.fill = GridBagConstraints.BOTH;
@ -461,13 +463,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
add(additionalCenterComp, gbConstraints); add(additionalCenterComp, gbConstraints);
} }
elementEditor.addPropertyChangeListener(new PropertyChangeListener() { elementEditor.addPropertyChangeListener(event -> repaint());
@Override
public void propertyChange(final PropertyChangeEvent event) {
repaint();
}
});
addPopupMenu(); addPopupMenu();
} catch (Exception ex) { } catch (Exception ex) {
@ -493,8 +489,8 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
* @return * @return
*/ */
private LayoutManager getButtonLayout(int additionalOffset, List<JButton> bList) { private LayoutManager getButtonLayout(int additionalOffset, List<JButton> bList) {
int lines = 1 + ((bList.size() + additionalOffset - 1) / 3);
int cols = 3; int cols = 3;
int lines = 1 + ((bList.size() + additionalOffset - 1) / cols);
return new GridLayout(lines, cols); return new GridLayout(lines, cols);
} }
@ -531,15 +527,11 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
* @return * @return
*/ */
private ActionListener makeSelectionKnownAL(final ActionListener al) { private ActionListener makeSelectionKnownAL(final ActionListener al) {
return new ActionListener() { return e -> {
if (selectableList != null) {
@Override selectableList.setSelectionByIndices(elementList.getSelectedIndices());
public void actionPerformed(ActionEvent e) {
if (selectableList != null) {
selectableList.setSelectionByIndices(elementList.getSelectedIndices());
}
al.actionPerformed(e);
} }
al.actionPerformed(e);
}; };
} }
@ -576,12 +568,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
} }
public boolean areAllSelected() { public boolean areAllSelected() {
for (int i = 0; i < elementList.getModel().getSize(); i++) { return elementList.getSelectedIndices().length == elementList.getModel().getSize();
if (!elementList.isSelectedIndex(i)) {
return false;
}
}
return true;
} }
/** /**
@ -647,7 +634,6 @@ public class ArrayEditor extends JPanel implements PropertyEditor {
private JMenuItem createMenuItem(String title, boolean enabled, private JMenuItem createMenuItem(String title, boolean enabled,
ActionListener aListener) { ActionListener aListener) {
JMenuItem item = new JMenuItem(title); JMenuItem item = new JMenuItem(title);
// if (bgColor!=null) item.setForeground(bgColor);
item.addActionListener(aListener); item.addActionListener(aListener);
item.setEnabled(enabled); item.setEnabled(enabled);
return item; return item;

View File

@ -0,0 +1,213 @@
package eva2.gui.editor;
import eva2.gui.*;
import eva2.tools.StringTools;
import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyEditor;
import java.lang.reflect.Array;
/**
* Created by halfdan on 17/12/15.
*/
public class ObjectArrayEditor<T> extends JPanel implements PropertyEditor {
private T[] value;
private JList<T> objectList;
private DefaultListModel<T> listModel;
private PropertyChangeSupport propChangeSupport;
public ObjectArrayEditor(Class<T> type) {
listModel = new DefaultListModel<>();
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = 2;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
c.weighty = 0.0;
c.gridx = 0;
c.gridy = 0;
TypeSelector typeSelector = new TypeSelector();
typeSelector.updateClassType(type.getName());
add(typeSelector, c);
JButton addButton = new JButton("Add");
c.gridwidth = 1;
c.gridx = 2;
c.gridy = 0;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
c.weighty = 0.0;
add(addButton, c);
JButton removeButton = new JButton("Remove");
c.gridx = 2;
c.gridy = 1;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
c.weighty = 0.0;
add(removeButton, c);
JButton configButton;
configButton = new JButton("Config");
c.gridx = 2;
c.gridy = 2;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
c.weighty = 0.0;
add(configButton, c);
objectList = new JList<>(listModel);
objectList.setVisibleRowCount(10);
c.gridwidth = 2;
c.gridheight = 5;
c.gridx = 0;
c.gridy = 1;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
JScrollPane scrollPane = new JScrollPane(objectList);
add(scrollPane, c);
addButton.addActionListener(event -> {
String className = ((Item) typeSelector.getSelectedItem()).getId();
try {
T n = (T) Class.forName(className).newInstance();
listModel.addElement(n);
propChangeSupport.firePropertyChange("", null, null);
} catch (Exception ex) {
System.err.println("Exception in itemStateChanged " + ex.getMessage());
System.err.println("Classpath is " + System.getProperty("java.class.path"));
ex.printStackTrace();
JOptionPane.showMessageDialog(this,
"Could not create an example of\n"
+ className + "\n"
+ "from the current classpath. Is the resource folder at the right place?\nIs the class abstract or the default constructor missing?",
"GenericObjectEditor",
JOptionPane.ERROR_MESSAGE);
}
});
removeButton.addActionListener(event -> {
if (!objectList.isSelectionEmpty()) {
listModel.remove(objectList.getSelectedIndex());
propChangeSupport.firePropertyChange("", null, null);
}
});
configButton.addActionListener(event -> {
T selected = objectList.getSelectedValue();
PropertyEditor editor = PropertyEditorProvider.findEditor(selected.getClass());
editor.setValue(selected);
PropertyDialog propertyDialog = new PropertyDialog(null, editor, StringTools.cutClassName(editor.getClass().getName()));
propertyDialog.setPreferredSize(new Dimension(500, 300));
propertyDialog.setModal(true);
propertyDialog.setVisible(true);
propChangeSupport.firePropertyChange("", null, null);
});
}
@Override
public void setValue(Object value) {
this.value = (T[])value;
listModel.removeAllElements();
for(T i : this.value) {
listModel.addElement(i);
}
}
@Override
public Object getValue() {
if (listModel == null) {
return null;
}
if (true == false) {
return true;
} else {
// Convert the listmodel to an array of strings and return it.
int length = listModel.getSize();
Object result = Array.newInstance(value.getClass().getComponentType(), length);
for (int i = 0; i < length; i++) {
Array.set(result, i, listModel.elementAt(i));
}
return result;
}
}
@Override
public boolean isPaintable() {
return true;
}
@Override
public void paintValue(Graphics gfx, Rectangle box) {
FontMetrics fm = gfx.getFontMetrics();
int vpad = (box.height - fm.getAscent()) / 2;
String rep;
if (listModel.getSize() == 0) {
rep = "Empty";
} else {
rep = listModel.getSize() + " of " + StringTools.cutClassName(value.getClass().getComponentType().getName());
Object maybeName = BeanInspector.callIfAvailable(listModel.get(0), "getName", new Object[]{});
if (maybeName != null) {
rep = rep + " (" + maybeName + "...)";
}
}
gfx.drawString(rep, 2, fm.getHeight() + vpad - 3);
}
@Override
public String getJavaInitializationString() {
return null;
}
@Override
public String getAsText() {
return null;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
throw new IllegalArgumentException(text);
}
@Override
public String[] getTags() {
return new String[0];
}
@Override
public Component getCustomEditor() {
return this;
}
@Override
public boolean supportsCustomEditor() {
return true;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
if (propChangeSupport == null) {
propChangeSupport = new PropertyChangeSupport(this);
}
propChangeSupport.addPropertyChangeListener(l);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
if (propChangeSupport == null) {
propChangeSupport = new PropertyChangeSupport(this);
}
propChangeSupport.removePropertyChangeListener(l);
}
}

View File

@ -0,0 +1,33 @@
package eva2.tools;
import java.util.HashMap;
import java.util.Map;
/**
* Created by halfdan on 17/12/15.
*/
public class Primitives {
public static Class<?> unwrap(Class<?> clazz) {
return getWrapperTypes().get(clazz);
}
public static boolean isWrapperType(Class<?> clazz)
{
return getWrapperTypes().containsKey(clazz);
}
private static Map<Class<?>, Class<?>> getWrapperTypes()
{
Map<Class<?>, Class<?>> ret = new HashMap<>();
ret.put(Boolean.class, boolean.class);
ret.put(Character.class, char.class);
ret.put(Byte.class, byte.class);
ret.put(Short.class, short.class);
ret.put(Integer.class, int.class);
ret.put(Long.class, long.class);
ret.put(Float.class, float.class);
ret.put(Double.class, double.class);
ret.put(Void.class, void.class);
return ret;
}
}