Merge branch 'object-array-editor' into 'master'
Object array editor This introduces a new generic ObjectArrayEditor which allows adding assignable classes of a type T to a list (shown in a JList) and configuring those objects in a GenericObjectEditor instance.  This thing is useful in multiple instances: - MetaEvA - To select problems and configure them (dimension, init range, etc.) - To select optimizers (configuration will be ignored) - Experiment Generator (future project) - To select problems and configure optimizer to be executed in a run matrix ToDo: - [x] Allow deactivating/hiding the "Config" button - [x] Make sure this will automatically be used for objects that have an `Anything[]` - [x] Find a way to get a better `toString()` (CEC2005 for some reason looks fine) See merge request !10
This commit is contained in:
		| @@ -4,23 +4,17 @@ import eva2.gui.editor.GenericObjectEditor; | ||||
| import eva2.optimization.tools.FileTools; | ||||
| import eva2.tools.BasicResourceLoader; | ||||
| import eva2.tools.SerializedObject; | ||||
| import eva2.tools.StringTools; | ||||
| import eva2.util.annotation.Description; | ||||
| import eva2.yaml.BeanSerializer; | ||||
|  | ||||
| import javax.swing.*; | ||||
| import javax.swing.filechooser.FileFilter; | ||||
| import javax.swing.filechooser.FileNameExtensionFilter; | ||||
| import javax.swing.plaf.basic.BasicComboBoxRenderer; | ||||
| import java.awt.*; | ||||
| import java.awt.event.ActionListener; | ||||
| import java.awt.event.ItemEvent; | ||||
| import java.awt.event.ItemListener; | ||||
| import java.beans.PropertyChangeSupport; | ||||
| import java.lang.reflect.Proxy; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Vector; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| /** | ||||
| @@ -34,15 +28,11 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|     /** | ||||
|      * The chooser component | ||||
|      */ | ||||
|     private JComboBox<Item> objectChooser; | ||||
|     private TypeSelector typeSelector; | ||||
|     /** | ||||
|      * The component that performs classifier customization | ||||
|      */ | ||||
|     private PropertySheetPanel propertySheetPanel; | ||||
|     /** | ||||
|      * The model containing the list of names to select from | ||||
|      */ | ||||
|     private DefaultComboBoxModel<Item> comboBoxModel; | ||||
|     /** | ||||
|      * Open object from disk | ||||
|      */ | ||||
| @@ -77,9 +67,8 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|     } | ||||
|  | ||||
|     private void buildTypeSelectionPanel() { | ||||
|         comboBoxModel = new DefaultComboBoxModel<>(new Vector<>()); | ||||
|         objectChooser = new JComboBox<>(comboBoxModel); | ||||
|         objectChooser.setEditable(false); | ||||
|         typeSelector = new TypeSelector(); | ||||
|         typeSelector.setEditable(false); | ||||
|  | ||||
|         GridBagConstraints gbConstraints = new GridBagConstraints(); | ||||
|  | ||||
| @@ -89,7 +78,7 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|         gbConstraints.gridy = 0; | ||||
|  | ||||
|         JLabel typeLabel = new JLabel("Type:"); | ||||
|         typeLabel.setLabelFor(objectChooser); | ||||
|         typeLabel.setLabelFor(typeSelector); | ||||
|         typeLabel.setDisplayedMnemonic('t'); | ||||
|         typeSelectionPanel.add(typeLabel, gbConstraints); | ||||
|  | ||||
| @@ -97,7 +86,7 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|         gbConstraints.gridy = 0; | ||||
|         gbConstraints.weightx = 1.0; | ||||
|         gbConstraints.fill = GridBagConstraints.HORIZONTAL; | ||||
|         typeSelectionPanel.add(objectChooser, gbConstraints); | ||||
|         typeSelectionPanel.add(typeSelector, gbConstraints); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -181,9 +170,6 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|             ((JDialog) container).dispose(); | ||||
|         }); | ||||
|  | ||||
|         // 10px padding | ||||
|         setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | ||||
|  | ||||
|         setLayout(new GridBagLayout()); | ||||
|         GridBagConstraints gbConstraints = new GridBagConstraints(); | ||||
|  | ||||
| @@ -225,7 +211,7 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|             updateChooser(); | ||||
|             updateChildPropertySheet(); | ||||
|         } | ||||
|         objectChooser.addItemListener(this); | ||||
|         typeSelector.addItemListener(this); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -317,59 +303,24 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|      * | ||||
|      */ | ||||
|     public void updateClassType() { | ||||
|         List<String> classesLongNames; | ||||
|         ArrayList<Class<?>> instances = new ArrayList<>(5); | ||||
|         classesLongNames = GenericObjectEditor.getClassesFromProperties(genericObjectEditor.getClassType().getName(), instances); | ||||
|         LOGGER.finest("Selected type for OptimizationEditorPanel: " + genericObjectEditor.getClassType().getName()); | ||||
|         if (classesLongNames.size() > 1) { | ||||
|             Vector<Item> classesList = new Vector<>(); | ||||
|             String[] toolTips = collectComboToolTips(instances, tipMaxLen); | ||||
|             int i = 0; | ||||
|             for (String className : classesLongNames) { | ||||
|                 String displayName = StringTools.cutClassName(className); | ||||
|         typeSelector.updateClassType(genericObjectEditor.getClassType().getName()); | ||||
|  | ||||
|                 classesList.add(new Item(className, displayName, toolTips[i++])); | ||||
|             } | ||||
|             comboBoxModel = new DefaultComboBoxModel<>(classesList); | ||||
|             objectChooser.setModel(comboBoxModel); | ||||
|             objectChooser.setRenderer(new ToolTipComboBoxRenderer()); | ||||
|         if (typeSelector.getItemCount() > 1) { | ||||
|             typeSelectionPanel.setVisible(true); | ||||
|         } else { | ||||
|             typeSelectionPanel.setVisible(false); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private String[] collectComboToolTips(List<Class<?>> instances, int maxLen) { | ||||
|         String[] tips = new String[instances.size()]; | ||||
|  | ||||
|         for (int i = 0; i < tips.length; i++) { | ||||
|             tips[i] = null; | ||||
|  | ||||
|             String tip = null; | ||||
|  | ||||
|             Description description = instances.get(i).getAnnotation(Description.class); | ||||
|             if (description != null) { | ||||
|                 tip = description.value(); | ||||
|             } | ||||
|  | ||||
|             if (tip != null) { | ||||
|                 if (tip.length() <= maxLen) { | ||||
|                     tips[i] = tip; | ||||
|                 } else { | ||||
|                     tips[i] = tip.substring(0, maxLen - 2) + ".."; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return tips; | ||||
|     } | ||||
|  | ||||
|     public void updateChooser() { | ||||
|         String objectName = genericObjectEditor.getValue().getClass().getName(); | ||||
|         for (int i = 0; i < comboBoxModel.getSize(); i++) { | ||||
|             Item element = comboBoxModel.getElementAt(i); | ||||
|         for (int i = 0; i < typeSelector.getItemCount(); i++) { | ||||
|             TypeSelectorItem element = typeSelector.getItemAt(i); | ||||
|  | ||||
|             if (objectName.equals(element.getId())) { | ||||
|                 objectChooser.getModel().setSelectedItem(element); | ||||
|                 typeSelector.getModel().setSelectedItem(element); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| @@ -393,8 +344,8 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|     public void itemStateChanged(ItemEvent e) { | ||||
|         String className; | ||||
|  | ||||
|         if ((e.getSource() == objectChooser) && (e.getStateChange() == ItemEvent.SELECTED)) { | ||||
|             className = ((Item)objectChooser.getSelectedItem()).getId(); | ||||
|         if ((e.getSource() == typeSelector) && (e.getStateChange() == ItemEvent.SELECTED)) { | ||||
|             className = ((TypeSelectorItem) typeSelector.getSelectedItem()).getId(); | ||||
|             try { | ||||
|                 Object n = Class.forName(className).newInstance(); | ||||
|                 genericObjectEditor.setValue(n); | ||||
| @@ -403,8 +354,8 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|                 System.err.println("Exception in itemStateChanged " + ex.getMessage()); | ||||
|                 System.err.println("Classpath is " + System.getProperty("java.class.path")); | ||||
|                 ex.printStackTrace(); | ||||
|                 objectChooser.hidePopup(); | ||||
|                 objectChooser.setSelectedIndex(0); | ||||
|                 typeSelector.hidePopup(); | ||||
|                 typeSelector.setSelectedIndex(0); | ||||
|                 JOptionPane.showMessageDialog(this, | ||||
|                         "Could not create an example of\n" | ||||
|                                 + className + "\n" | ||||
| @@ -415,75 +366,3 @@ public class OptimizationEditorPanel extends JPanel implements ItemListener { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| class ToolTipComboBoxRenderer extends BasicComboBoxRenderer { | ||||
|  | ||||
|     private static final long serialVersionUID = -5781643352198561208L; | ||||
|  | ||||
|     public ToolTipComboBoxRenderer() { | ||||
|         super(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Component getListCellRendererComponent(JList list, Object value, | ||||
|                                                   int index, boolean isSelected, boolean cellHasFocus) { | ||||
|  | ||||
|         super.getListCellRendererComponent(list, value, index, | ||||
|                 isSelected, cellHasFocus); | ||||
|  | ||||
|         if (value != null) { | ||||
|             Item item = (Item)value; | ||||
|             setText(item.getDisplayName()); | ||||
|  | ||||
|             if (isSelected) { | ||||
|                 setBackground(list.getSelectionBackground()); | ||||
|                 setForeground(list.getSelectionForeground()); | ||||
|                 list.setToolTipText(item.getDescription()); | ||||
|             } else { | ||||
|                 setBackground(list.getBackground()); | ||||
|                 setForeground(list.getForeground()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (index == -1) { | ||||
|             Item item = (Item)value; | ||||
|             setText(item.getDisplayName()); | ||||
|         } | ||||
|  | ||||
|         setFont(list.getFont()); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
|  | ||||
| class Item | ||||
| { | ||||
|     private String id; | ||||
|     private String displayName; | ||||
|     private String description; | ||||
|  | ||||
|     public Item(String id, String displayName, String description) | ||||
|     { | ||||
|         this.id = id; | ||||
|         this.displayName = displayName; | ||||
|         this.description = description; | ||||
|     } | ||||
|  | ||||
|     public String getId() | ||||
|     { | ||||
|         return id; | ||||
|     } | ||||
|  | ||||
|     public String getDescription() | ||||
|     { | ||||
|         return description; | ||||
|     } | ||||
|  | ||||
|     public String getDisplayName() { | ||||
|         return displayName; | ||||
|     } | ||||
|  | ||||
|     public String toString() | ||||
|     { | ||||
|         return id; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -26,6 +26,8 @@ public class PropertyDialog extends JDialog { | ||||
|         setLayout(new BorderLayout()); | ||||
|         propertyEditor = editor; | ||||
|         editorComponent = editor.getCustomEditor(); | ||||
|  | ||||
|         ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | ||||
|         add(editorComponent, BorderLayout.CENTER); | ||||
|  | ||||
|         pack(); | ||||
|   | ||||
| @@ -3,12 +3,17 @@ package eva2.gui; | ||||
| import eva2.gui.editor.*; | ||||
| import eva2.optimization.individuals.codings.gp.GPArea; | ||||
| import eva2.optimization.operator.terminators.InterfaceTerminator; | ||||
| import eva2.tools.Primitives; | ||||
| import eva2.tools.SelectedTag; | ||||
| import eva2.tools.StringSelection; | ||||
|  | ||||
| import java.beans.PropertyDescriptor; | ||||
| import java.beans.PropertyEditor; | ||||
| import java.beans.PropertyEditorManager; | ||||
| import java.util.HashMap; | ||||
| import java.util.HashSet; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
|  | ||||
| public class PropertyEditorProvider { | ||||
|     // 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) { | ||||
|         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 (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()) { | ||||
|                 editor = new EnumEditor(); | ||||
|             } else { | ||||
|                 editor = new GenericObjectEditor(); | ||||
|                 ((GenericObjectEditor)editor).setClassType(cls); | ||||
|             } | ||||
|         } | ||||
|         return editor; | ||||
| @@ -42,6 +58,7 @@ public class PropertyEditorProvider { | ||||
|      * @return | ||||
|      */ | ||||
|     public static PropertyEditor findEditor(PropertyDescriptor prop, Object value) { | ||||
|  | ||||
|         PropertyEditor editor = null; | ||||
|         Class pec = prop.getPropertyEditorClass(); | ||||
|         Class type = prop.getPropertyType(); | ||||
| @@ -56,10 +73,9 @@ public class PropertyEditorProvider { | ||||
|  | ||||
|         if (editor == null) { | ||||
|             if (value != null) { | ||||
|  | ||||
|                 // ToDo: This should be handled by the registerEditor below. findEditor however always returns the sun.beans.editor stuff. | ||||
|                 if (value instanceof Enum) { | ||||
|                     editor = new EnumEditor(); | ||||
|                 // Try to unwrap primitives | ||||
|                 if (Primitives.isWrapperType(value.getClass())) { | ||||
|                     editor = PropertyEditorManager.findEditor(Primitives.unwrap(value.getClass())); | ||||
|                 } else { | ||||
|                     editor = PropertyEditorManager.findEditor(value.getClass()); | ||||
|                 } | ||||
| @@ -84,11 +100,17 @@ public class PropertyEditorProvider { | ||||
|  | ||||
|             if ((editor == null) && useDefaultGOE) { | ||||
|                 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()) { | ||||
|                     editor = new EnumEditor(); | ||||
|                 } else { | ||||
|                     editor = new GenericObjectEditor(); | ||||
|                     ((GenericObjectEditor)editor).setClassType(type); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -116,6 +138,8 @@ public class PropertyEditorProvider { | ||||
|         PropertyEditorManager.registerEditor(Enum.class, EnumEditor.class); | ||||
|         PropertyEditorManager.registerEditor(int[].class, ArrayEditor.class); | ||||
|         PropertyEditorManager.registerEditor(double[].class, ArrayEditor.class); | ||||
|         PropertyEditorManager.registerEditor(String[].class, ArrayEditor.class); | ||||
|  | ||||
|         PropertyEditorManager.registerEditor(InterfaceTerminator[].class, ArrayEditor.class); | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -227,7 +227,7 @@ public final class PropertySheetPanel extends JPanel implements PropertyChangeLi | ||||
|                 gbConstraints.fill = GridBagConstraints.HORIZONTAL; | ||||
|                 gbConstraints.anchor = GridBagConstraints.PAGE_START; | ||||
|  | ||||
|                 add(buildTitledSeperator("Info"), gbConstraints); | ||||
|                 add(new TitledSeparator("Info"), gbConstraints); | ||||
|  | ||||
|                 gbConstraints.gridy = 1; | ||||
|                 add(infoPanel, gbConstraints); | ||||
| @@ -307,9 +307,7 @@ public final class PropertySheetPanel extends JPanel implements PropertyChangeLi | ||||
|  | ||||
|  | ||||
|         gbConstraints.gridy = 2; | ||||
|  | ||||
|  | ||||
|         add(buildTitledSeperator("Properties"), gbConstraints); | ||||
|         add(new TitledSeparator("Properties"), gbConstraints); | ||||
|  | ||||
|         JScrollPane scrollableTable = new JScrollPane(propertyTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); | ||||
|         gbConstraints.gridx = 0; | ||||
| @@ -320,6 +318,8 @@ public final class PropertySheetPanel extends JPanel implements PropertyChangeLi | ||||
|         scrollableTable.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); | ||||
|         add(scrollableTable, gbConstraints); | ||||
|  | ||||
|         setMinimumSize(new Dimension(350, 0)); | ||||
|  | ||||
|         validate(); | ||||
|         setVisible(true); | ||||
|     } | ||||
| @@ -333,24 +333,6 @@ public final class PropertySheetPanel extends JPanel implements PropertyChangeLi | ||||
|         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) { | ||||
|         BeanInfo bi; | ||||
|         try { | ||||
|   | ||||
| @@ -59,6 +59,8 @@ public class TabbedFrameMaker implements Serializable, PanelMaker, InterfaceNoti | ||||
|  | ||||
|         for (PanelMaker element : pmContainer) { | ||||
|             JComponent panel = element.makePanel(); | ||||
|  | ||||
|             panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | ||||
|             if (element instanceof ModuleButtonPanelMaker) { | ||||
|                 extToolBar.add(panel); | ||||
|                 butPanelMkr = (ModuleButtonPanelMaker) element; | ||||
|   | ||||
							
								
								
									
										25
									
								
								src/main/java/eva2/gui/TitledSeparator.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/main/java/eva2/gui/TitledSeparator.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| package eva2.gui; | ||||
|  | ||||
| import javax.swing.*; | ||||
| import java.awt.*; | ||||
|  | ||||
| /** | ||||
|  * Created by halfdan on 17/12/15. | ||||
|  */ | ||||
| public final class TitledSeparator extends JPanel { | ||||
|     public TitledSeparator(String title) { | ||||
|         setLayout(new GridBagLayout()); | ||||
|  | ||||
|         GridBagConstraints gbConstraints = new GridBagConstraints(); | ||||
|         gbConstraints.gridx = 0; | ||||
|         gbConstraints.gridy = 0; | ||||
|  | ||||
|         add(new JLabel("<html><b>" + title), gbConstraints); | ||||
|  | ||||
|         gbConstraints.gridx = 1; | ||||
|         gbConstraints.gridy = 0; | ||||
|         gbConstraints.weightx = 1.0; | ||||
|         gbConstraints.fill = GridBagConstraints.HORIZONTAL; | ||||
|         add(new JSeparator(JSeparator.HORIZONTAL), gbConstraints); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										114
									
								
								src/main/java/eva2/gui/TypeSelector.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/main/java/eva2/gui/TypeSelector.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| package eva2.gui; | ||||
|  | ||||
| import eva2.gui.editor.GenericObjectEditor; | ||||
| import eva2.tools.StringTools; | ||||
| import eva2.util.annotation.Description; | ||||
|  | ||||
| import javax.swing.*; | ||||
| import javax.swing.plaf.basic.BasicComboBoxRenderer; | ||||
| import java.awt.*; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Vector; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| /** | ||||
|  * Created by fabian on 16/12/15. | ||||
|  */ | ||||
| public class TypeSelector extends JComboBox<TypeSelectorItem> { | ||||
|     private static final Logger LOGGER = Logger.getLogger(TypeSelector.class.getName()); | ||||
|     /** | ||||
|      * The model containing the list of names to select from | ||||
|      */ | ||||
|     private DefaultComboBoxModel<TypeSelectorItem> comboBoxModel; | ||||
|  | ||||
|     public TypeSelector() { | ||||
|  | ||||
|         comboBoxModel = new DefaultComboBoxModel<>(new Vector<>()); | ||||
|     } | ||||
|  | ||||
|     public void updateClassType(String classTypeName) { | ||||
|         java.util.List<String> classesLongNames; | ||||
|         ArrayList<Class<?>> instances = new ArrayList<>(5); | ||||
|         classesLongNames = GenericObjectEditor.getClassesFromProperties(classTypeName, instances); | ||||
|         LOGGER.finest("Selected type for OptimizationEditorPanel: " + classTypeName); | ||||
|         if (classesLongNames.size() > 1) { | ||||
|             Vector<TypeSelectorItem> classesList = new Vector<>(); | ||||
|             String[] toolTips = collectComboToolTips(instances, 100); | ||||
|             int i = 0; | ||||
|             for (String className : classesLongNames) { | ||||
|                 String displayName = StringTools.cutClassName(className); | ||||
|  | ||||
|                 classesList.add(new TypeSelectorItem(className, displayName, toolTips[i++])); | ||||
|             } | ||||
|             comboBoxModel = new DefaultComboBoxModel<>(classesList); | ||||
|             this.setModel(comboBoxModel); | ||||
|             this.setRenderer(new ToolTipComboBoxRenderer()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private String[] collectComboToolTips(List<Class<?>> instances, int maxLen) { | ||||
|         String[] tips = new String[instances.size()]; | ||||
|  | ||||
|         for (int i = 0; i < tips.length; i++) { | ||||
|             tips[i] = null; | ||||
|  | ||||
|             String tip = null; | ||||
|  | ||||
|             Description description = instances.get(i).getAnnotation(Description.class); | ||||
|             if (description != null) { | ||||
|                 tip = description.value(); | ||||
|             } | ||||
|  | ||||
|             if (tip != null) { | ||||
|                 if (tip.length() <= maxLen) { | ||||
|                     tips[i] = tip; | ||||
|                 } else { | ||||
|                     tips[i] = tip.substring(0, maxLen - 2) + ".."; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return tips; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| class ToolTipComboBoxRenderer extends BasicComboBoxRenderer { | ||||
|  | ||||
|     private static final long serialVersionUID = -5781643352198561208L; | ||||
|  | ||||
|     public ToolTipComboBoxRenderer() { | ||||
|         super(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Component getListCellRendererComponent(JList list, Object value, | ||||
|                                                   int index, boolean isSelected, boolean cellHasFocus) { | ||||
|  | ||||
|         super.getListCellRendererComponent(list, value, index, | ||||
|                 isSelected, cellHasFocus); | ||||
|  | ||||
|         if (value != null) { | ||||
|             TypeSelectorItem item = (TypeSelectorItem)value; | ||||
|             setText(item.getDisplayName()); | ||||
|  | ||||
|             if (isSelected) { | ||||
|                 setBackground(list.getSelectionBackground()); | ||||
|                 setForeground(list.getSelectionForeground()); | ||||
|                 list.setToolTipText(item.getDescription()); | ||||
|             } else { | ||||
|                 setBackground(list.getBackground()); | ||||
|                 setForeground(list.getForeground()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (index == -1) { | ||||
|             TypeSelectorItem item = (TypeSelectorItem)value; | ||||
|             setText(item.getDisplayName()); | ||||
|         } | ||||
|  | ||||
|         setFont(list.getFont()); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										34
									
								
								src/main/java/eva2/gui/TypeSelectorItem.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/main/java/eva2/gui/TypeSelectorItem.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| package eva2.gui; | ||||
|  | ||||
| public class TypeSelectorItem | ||||
| { | ||||
|     private String id; | ||||
|     private String displayName; | ||||
|     private String description; | ||||
|  | ||||
|     public TypeSelectorItem(String id, String displayName, String description) | ||||
|     { | ||||
|         this.id = id; | ||||
|         this.displayName = displayName; | ||||
|         this.description = description; | ||||
|     } | ||||
|  | ||||
|     public String getId() | ||||
|     { | ||||
|         return id; | ||||
|     } | ||||
|  | ||||
|     public String getDescription() | ||||
|     { | ||||
|         return description; | ||||
|     } | ||||
|  | ||||
|     public String getDisplayName() { | ||||
|         return displayName; | ||||
|     } | ||||
|  | ||||
|     public String toString() | ||||
|     { | ||||
|         return id; | ||||
|     } | ||||
| } | ||||
| @@ -79,7 +79,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|  | ||||
|         @Override | ||||
|         public void actionPerformed(ActionEvent e) { | ||||
|             boolean consistentView = true; // be optimistic... | ||||
|             boolean consistentView; | ||||
|             if (view instanceof PropertyText) { // check consistency! | ||||
|                 consistentView = ((PropertyText) view).checkConsistency(); | ||||
|                 if (!consistentView) { | ||||
| @@ -238,7 +238,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|                     list.ensureIndexIsVisible(index); | ||||
|                     propPanel.getEditor().setValue(item); | ||||
|                     propPanel.showDialog(); | ||||
|                     propPanel = null; | ||||
|  | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -291,7 +291,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|                     ((GenericObjectEditor) e).setClassType(valueClass); | ||||
|                 } | ||||
|                 e.setValue(value); | ||||
|                 JPanel cellPanel = new JPanel() { | ||||
|                 return new JPanel() { | ||||
|  | ||||
|                     @Override | ||||
|                     public void paintComponent(Graphics g) { | ||||
| @@ -315,7 +315,6 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|                         return newPref; | ||||
|                     } | ||||
|                 }; | ||||
|                 return cellPanel; | ||||
|             } catch (Exception ex) { | ||||
|                 return null; | ||||
|             } | ||||
| @@ -401,7 +400,6 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     //setPreferredSize(new Dimension(400,500)); | ||||
|  | ||||
|                     if (withAddButton && !(upperButtonList.contains(addButton))) { | ||||
|                         upperButtonList.add(addButton); | ||||
| @@ -415,9 +413,6 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|  | ||||
|                     // Upper Button Panel | ||||
|                     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) { | ||||
|                         combiUpperPanel.add(but); | ||||
| @@ -431,6 +426,12 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|                     gbConstraints.gridy = 0; | ||||
|                     add(combiUpperPanel, gbConstraints); | ||||
|  | ||||
|                     gbConstraints.gridy++; | ||||
|                     gbConstraints.fill = GridBagConstraints.HORIZONTAL; | ||||
|                     gbConstraints.weightx = 1.0; | ||||
|                     add(view, gbConstraints); | ||||
|                     view.setVisible(withAddButton); | ||||
|  | ||||
|                     // Job List | ||||
|                     gbConstraints.gridy++; | ||||
|                     gbConstraints.fill = GridBagConstraints.BOTH; | ||||
| @@ -461,13 +462,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|                         add(additionalCenterComp, gbConstraints); | ||||
|                     } | ||||
|  | ||||
|                     elementEditor.addPropertyChangeListener(new PropertyChangeListener() { | ||||
|  | ||||
|                         @Override | ||||
|                         public void propertyChange(final PropertyChangeEvent event) { | ||||
|                             repaint(); | ||||
|                         } | ||||
|                     }); | ||||
|                     elementEditor.addPropertyChangeListener(event -> repaint()); | ||||
|  | ||||
|                     addPopupMenu(); | ||||
|                 } catch (Exception ex) { | ||||
| @@ -493,8 +488,8 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|      * @return | ||||
|      */ | ||||
|     private LayoutManager getButtonLayout(int additionalOffset, List<JButton> bList) { | ||||
|         int lines = 1 + ((bList.size() + additionalOffset - 1) / 3); | ||||
|         int cols = 3; | ||||
|         int lines = 1 + ((bList.size() + additionalOffset - 1) / cols); | ||||
|         return new GridLayout(lines, cols); | ||||
|     } | ||||
|  | ||||
| @@ -531,15 +526,11 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|      * @return | ||||
|      */ | ||||
|     private ActionListener makeSelectionKnownAL(final ActionListener al) { | ||||
|         return new ActionListener() { | ||||
|  | ||||
|             @Override | ||||
|             public void actionPerformed(ActionEvent e) { | ||||
|                 if (selectableList != null) { | ||||
|                     selectableList.setSelectionByIndices(elementList.getSelectedIndices()); | ||||
|                 } | ||||
|                 al.actionPerformed(e); | ||||
|         return e -> { | ||||
|             if (selectableList != null) { | ||||
|                 selectableList.setSelectionByIndices(elementList.getSelectedIndices()); | ||||
|             } | ||||
|             al.actionPerformed(e); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
| @@ -576,12 +567,7 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|     } | ||||
|  | ||||
|     public boolean areAllSelected() { | ||||
|         for (int i = 0; i < elementList.getModel().getSize(); i++) { | ||||
|             if (!elementList.isSelectedIndex(i)) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|         return elementList.getSelectedIndices().length == elementList.getModel().getSize(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -647,7 +633,6 @@ public class ArrayEditor extends JPanel implements PropertyEditor { | ||||
|     private JMenuItem createMenuItem(String title, boolean enabled, | ||||
|                                      ActionListener aListener) { | ||||
|         JMenuItem item = new JMenuItem(title); | ||||
|         // if (bgColor!=null) item.setForeground(bgColor); | ||||
|         item.addActionListener(aListener); | ||||
|         item.setEnabled(enabled); | ||||
|         return item; | ||||
|   | ||||
							
								
								
									
										214
									
								
								src/main/java/eva2/gui/editor/ObjectArrayEditor.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								src/main/java/eva2/gui/editor/ObjectArrayEditor.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,214 @@ | ||||
| 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; | ||||
|     private JButton configButton; | ||||
|  | ||||
|     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); | ||||
|  | ||||
|         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 = ((TypeSelectorItem) 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; | ||||
|         } else { | ||||
|             // 	Convert the listmodel to an array of T 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); | ||||
|     } | ||||
|  | ||||
|     public void toggleConfigButton() { | ||||
|         this.configButton.setEnabled(!configButton.isEnabled()); | ||||
|     } | ||||
| } | ||||
| @@ -162,11 +162,8 @@ public class OptimizationJobList extends PropertySelectableList<OptimizationJob> | ||||
|                 (StatisticsOnTwoSampledData[]) StatisticalEvaluation.statsParams.getTwoSampledStats().getSelectedEnum(StatisticsOnTwoSampledData.values())); | ||||
|         ActionListener sl = e -> arrayEditor.selectDeselectAll(); | ||||
|  | ||||
|         ActionListener cliButtonListener = actionEvent -> System.out.println("Generating CLI call"); | ||||
|  | ||||
|         ActionListener sal = e -> jobList.saveSelectedJobs(arrayEditor); | ||||
|  | ||||
|         arrayEditor.addUpperActionButton("Get CLI", cliButtonListener); | ||||
|         arrayEditor.addUpperActionButton("(De-)Sel. all", sl); | ||||
|         arrayEditor.addUpperActionButton("Test Stats", al); | ||||
|  | ||||
|   | ||||
							
								
								
									
										33
									
								
								src/main/java/eva2/tools/Primitives.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/main/java/eva2/tools/Primitives.java
									
									
									
									
									
										Normal 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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										40
									
								
								src/test/java/eva2/gui/TypeSelectorItemTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/test/java/eva2/gui/TypeSelectorItemTest.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| package eva2.gui; | ||||
|  | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
|  | ||||
| import static org.junit.Assert.*; | ||||
|  | ||||
| public class TypeSelectorItemTest { | ||||
|     TypeSelectorItem item; | ||||
|  | ||||
|     @Before | ||||
|     public void setUp() throws Exception { | ||||
|         item = new TypeSelectorItem( | ||||
|                 "eva2.problem.AbstractProblemDouble", | ||||
|                 "AbstractProblemDouble", | ||||
|                 "An abstract problem" | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void testGetId() throws Exception { | ||||
|         assertEquals("eva2.problem.AbstractProblemDouble", item.getId()); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void testGetDescription() throws Exception { | ||||
|         assertEquals("An abstract problem", item.getDescription()); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void testGetDisplayName() throws Exception { | ||||
|         assertEquals("AbstractProblemDouble", item.getDisplayName()); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void testToString() throws Exception { | ||||
|         // Should match the id | ||||
|         assertEquals("eva2.problem.AbstractProblemDouble", item.toString()); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user