package javaeva.gui; /* * Title: JavaEvA * Description: * Copyright: Copyright (c) 2003 * Company: University of Tuebingen, Computer Architecture * @author Holger Ulmer, Felix Streichert, Hannes Planatscher * @version: $Revision: 266 $ * $Date: 2007-11-20 14:33:48 +0100 (Tue, 20 Nov 2007) $ * $Author: mkron $ */ import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.MethodDescriptor; import java.beans.PropertyDescriptor; import java.awt.*; import java.awt.event.*; import java.beans.PropertyEditor; import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyEditorManager; import java.io.File; import java.io.ObjectInputStream; import java.io.BufferedInputStream; import java.io.ObjectOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.BufferedOutputStream; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import java.util.*; import javax.swing.*; import javax.swing.border.LineBorder; import wsi.ra.jproxy.RMIProxyLocal; //import wsi.ra.tool.DummyCategory; import javaeva.client.EvAClient; import javaeva.tools.CompileAndLoad; import javaeva.tools.EVAHELP; import javaeva.tools.ReflectPackage; import javaeva.tools.Tag; import javaeva.tools.SelectedTag; import javaeva.tools.Serializer; import javaeva.server.stat.StatisticsParameter; import javaeva.server.stat.StatisticsParameterImpl; /*==========================================================================* * CLASS DECLARATION *==========================================================================*/ public class GenericObjectEditor implements PropertyEditor { static final public boolean TRACE = false; private Object m_Object; private Object m_Backup; private PropertyChangeSupport m_Support = new PropertyChangeSupport(this); private Class m_ClassType; private GOEPanel m_EditorComponent; private boolean m_Enabled = true; /** * */ public class GOEPanel extends JPanel implements ItemListener { /** The chooser component */ private JComboBox m_ObjectChooser; /** The component that performs classifier customization */ private PropertySheetPanel m_ChildPropertySheet; /** The model containing the list of names to select from */ private DefaultComboBoxModel m_ObjectNames; /** Open object from disk */ private JButton m_OpenBut; /** Save object to disk */ private JButton m_SaveBut; /** ok button */ public JButton m_okBut; /** cancel button */ private JButton m_cancelBut; /** edit source button */ // private JButton m_editSourceBut; /** The filechooser for opening and saving object files */ private JFileChooser m_FileChooser; /** Creates the GUI editor component */ private Vector m_ClassesLongName; // private String[] m_ClassesShortName; // private SourceCodeEditor m_SourceCodeEditor; // private PropertyDialog m_SourceCodeEditorFrame; /** * */ public GOEPanel() { //System.out.println("GOEPanel.Constructor !!"); if (!(Proxy.isProxyClass(m_Object.getClass()))) m_Backup = copyObject(m_Object); m_ObjectNames = new DefaultComboBoxModel(new String [0]); m_ObjectChooser = new JComboBox(m_ObjectNames); m_ObjectChooser.setEditable(false); m_ChildPropertySheet = new PropertySheetPanel(); m_ChildPropertySheet.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { m_Support.firePropertyChange("", m_Backup, m_Object); } }); m_OpenBut = new JButton("Open..."); m_OpenBut.setToolTipText("Load a configured object"); m_OpenBut.setEnabled(true); m_OpenBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Object object = openObject(); if (object != null) { // setValue takes care of: Making sure obj is of right type, // and firing property change. setValue(object); // Need a second setValue to get property values filled in OK. // Not sure why. setValue(object); // <- Hannes ?!?!? } } }); m_SaveBut = new JButton("Save..."); m_SaveBut.setToolTipText("Save the current configured object"); m_SaveBut.setEnabled(true); m_SaveBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { saveObject(m_Object); } }); // // m_editSourceBut = new JButton("Edit Source"); // m_editSourceBut.setToolTipText("Edit the Source"); // m_editSourceBut.setEnabled(false); // m_editSourceBut.addActionListener(new ActionListener() { // public void actionPerformed(ActionEvent e) { // m_editSourceBut.setEnabled(false); // m_SourceCodeEditor = new SourceCodeEditor(); // String className = m_Object.getClass().getName(); // m_SourceCodeEditor.editSource(EvAClient.DYNAMICCLASSES_PROPERTIES.getProperty(className)); // m_SourceCodeEditorFrame = new PropertyDialog(m_SourceCodeEditor, "test", 50, 50); // m_SourceCodeEditorFrame.pack(); // m_SourceCodeEditorFrame.addWindowListener(new WindowAdapter() { // public void windowClosing (WindowEvent e) { // m_SourceCodeEditor = null; // m_editSourceBut.setEnabled(true); // } // }); // m_SourceCodeEditor.addPropertyChangeListener(new // PropertyChangeListener() { // public void propertyChange(PropertyChangeEvent evt) { // sourceChanged(); // } // } // ); // } // }); m_okBut = new JButton("OK"); m_okBut.setEnabled(true); m_okBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_Backup = copyObject(m_Object); if ((getTopLevelAncestor() != null) && (getTopLevelAncestor() instanceof Window)) { Window w = (Window) getTopLevelAncestor(); w.dispose(); } } }); m_cancelBut = new JButton("Cancel"); m_cancelBut.setEnabled(false); m_cancelBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (m_Backup != null) { m_Object = copyObject(m_Backup); setObject(m_Object); updateClassType(); updateChooser(); updateChildPropertySheet(); } if ((getTopLevelAncestor() != null) && (getTopLevelAncestor() instanceof Window)) { Window w = (Window) getTopLevelAncestor(); w.dispose(); } } }); setLayout(new BorderLayout()); add(m_ObjectChooser, BorderLayout.NORTH); // important add(m_ChildPropertySheet, BorderLayout.CENTER); // Since we resize to the size of the property sheet, a scrollpane isn't // typically needed // add(new JScrollPane(m_ChildPropertySheet), BorderLayout.CENTER); JPanel okcButs = new JPanel(); okcButs.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); okcButs.setLayout(new GridLayout(1, 4, 5, 5)); okcButs.add(m_OpenBut); okcButs.add(m_SaveBut); okcButs.add(m_okBut); // okcButs.add(m_editSourceBut); //okcButs.add(m_cancelBut); add(okcButs, BorderLayout.SOUTH); if (m_ClassType != null) { updateClassType(); updateChooser(); updateChildPropertySheet(); } m_ObjectChooser.addItemListener(this); } /** * Opens an object from a file selected by the user. * * @return the loaded object, or null if the operation was cancelled */ protected Object openObject() { if (m_FileChooser == null) { createFileChooser(); } int returnVal = m_FileChooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { File selected = m_FileChooser.getSelectedFile(); try { ObjectInputStream oi = new ObjectInputStream(new BufferedInputStream(new FileInputStream(selected))); Object obj = oi.readObject(); oi.close(); if (!m_ClassType.isAssignableFrom(obj.getClass())) { throw new Exception("Object not of type: " + m_ClassType.getName()); } return obj; } catch (Exception ex) { JOptionPane.showMessageDialog(this, "Couldn't read object: " + selected.getName() + "\n" + ex.getMessage(), "Open object file", JOptionPane.ERROR_MESSAGE); } } return null; } /** Saves the current object to a file selected by the user. * @param object The object to save. */ protected void saveObject(Object object) { if (m_FileChooser == null) { createFileChooser(); } int returnVal = m_FileChooser.showSaveDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { File sFile = m_FileChooser.getSelectedFile(); try { ObjectOutputStream oo = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(sFile))); oo.writeObject(object); oo.close(); } catch (Exception ex) { JOptionPane.showMessageDialog(this, "Couldn't write to file: " + sFile.getName() + "\n" + ex.getMessage(), "Save object", JOptionPane.ERROR_MESSAGE); } } } protected void createFileChooser() { m_FileChooser = new JFileChooser(new File("/resources")); m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); } /** * Makes a copy of an object using serialization * @param source the object to copy * @return a copy of the source object */ protected Object copyObject(Object source) { Object result = null; try { SerializedObject so = new SerializedObject(source); result = so.getObject(); } catch (Exception ex) { System.err.println("GenericObjectEditor: Problem making backup object"); System.err.println(source.getClass().getName()); ex.printStackTrace(); } return result; } /** * This is used to hook an action listener to the ok button * @param a The action listener. */ public void addOkListener(ActionListener a) { m_okBut.addActionListener(a); } /** * This is used to hook an action listener to the cancel button * @param a The action listener. */ public void addCancelListener(ActionListener a) { m_cancelBut.addActionListener(a); } /** * This is used to remove an action listener from the ok button * @param a The action listener */ public void removeOkListener(ActionListener a) { m_okBut.removeActionListener(a); } /** * This is used to remove an action listener from the cancel button * @param a The action listener */ public void removeCancelListener(ActionListener a) { m_cancelBut.removeActionListener(a); } /** * */ protected void updateClassType() { if (TRACE) System.out.println("# updating class "+m_ClassType.getName()); if (Proxy.isProxyClass(m_ClassType)) { if (TRACE) System.out.println("PROXY! original was " + ((RMIProxyLocal)Proxy.getInvocationHandler(((Proxy)m_Object))).getOriginalClass().getName()); m_ClassesLongName = new Vector(getClassesFromProperties(((RMIProxyLocal)Proxy.getInvocationHandler(((Proxy)m_Object))).getOriginalClass().getName())); } else { m_ClassesLongName = new Vector(getClassesFromProperties(m_ClassType.getName())); } m_ObjectChooser.setModel(new DefaultComboBoxModel(m_ClassesLongName)); if (m_ClassesLongName.size() > 1) // testhu add(m_ObjectChooser, BorderLayout.NORTH); else remove(m_ObjectChooser); if (TRACE) System.out.println("# done updating class "+m_ClassType.getName()); } protected void updateChooser() { String objectName = /*EVAHELP.cutClassName*/ (m_Object.getClass().getName()); boolean found = false; for (int i = 0; i < m_ObjectNames.getSize(); i++) { if (TRACE) System.out.println("in updateChooser: looking at "+(String)m_ObjectNames.getElementAt(i)); if (objectName.equals((String)m_ObjectNames.getElementAt(i))) { found = true; break; } } if (!found) m_ObjectNames.addElement(objectName); m_ObjectChooser.getModel().setSelectedItem(objectName); } /** Updates the child property sheet, and creates if needed */ public void updateChildPropertySheet() { //System.err.println("GOE::updateChildPropertySheet()"); // Set the object as the target of the propertysheet m_ChildPropertySheet.setTarget(m_Object); // Adjust size of containing window if possible if ((getTopLevelAncestor() != null) && (getTopLevelAncestor() instanceof Window)) { ((Window) getTopLevelAncestor()).pack(); } } // // public void sourceChanged() { // // //System.out.println("SOURCESTATECHANGED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! "); // String className = (String) m_ObjectChooser.getSelectedItem(); // //// @todohannes: hack! ausbessern // className = (String) m_ObjectChooser.getSelectedItem(); // try { // if (m_userdefclasses == true) { // className = m_Object.getClass().getName(); // Object[] para = new Object[] {}; // Object n = (Object) CompileAndLoad.getInstanceFull( // EvAClient.DYNAMICCLASSES_PROPERTIES.getProperty(className), // className, // para); // setObject(n); // } // else { // System.out.println("m_userdefclasses == false!!!!!"); // } // } // catch (Exception ex) { // } // // } /** * When the chooser selection is changed, ensures that the Object * is changed appropriately. * * @param e a value of type 'ItemEvent' */ public void itemStateChanged(ItemEvent e) { String className = (String)m_ObjectChooser.getSelectedItem(); // m_editSourceBut.setEnabled(false); // @todohannes: hack! ausbessern // try { // if (EvAClient.DYNAMICCLASSES_PROPERTIES.containsKey(className) && m_userdefclasses) { // m_editSourceBut.setEnabled(true); // } // } catch (Exception e1) { // System.out.println("Fehler !!! " + e1); // } // @todohannes: hack! ausbessern // // if (this.m_SourceCodeEditorFrame != null) { // m_SourceCodeEditorFrame.setVisible(false); // m_SourceCodeEditorFrame = null; // m_SourceCodeEditor = null; // } if (TRACE) System.out.println("Event-Quelle: " + e.getSource().toString()); if ((e.getSource() == m_ObjectChooser) && (e.getStateChange() == ItemEvent.SELECTED)){ className = (String)m_ObjectChooser.getSelectedItem(); try { // if (EvAClient.DYNAMICCLASSES_PROPERTIES.containsKey(className) && m_userdefclasses) { // Object[] para = new Object[] {}; // String source = EvAClient.DYNAMICCLASSES_PROPERTIES.getProperty(className); // Object dummy = CompileAndLoad.getInstanceFull(source,className,para); // setObject(dummy); // } else { if (TRACE) System.out.println(className); Object n = (Object)Class.forName(className, true, ClassLoader.getSystemClassLoader()).newInstance(); n = (Object)Class.forName(className).newInstance(); setObject(n); // } } catch (Exception ex) { System.out.println("Exeption in itemStateChanged "+ex.getMessage()); ex.printStackTrace(); m_ObjectChooser.hidePopup(); m_ObjectChooser.setSelectedIndex(0); JOptionPane.showMessageDialog(this, "Could not create an example of\n" + className + "\n" + "from the current classpath. Is it abstract? Is the default constructor missing?", "GenericObjectEditor", JOptionPane.ERROR_MESSAGE); EVAHELP.getSystemPropertyString(); } } } } // end of inner class /** * Read the classes available for user selection from the properties or the classpath respectively */ public static ArrayList getClassesFromProperties(String className) { if (TRACE) System.out.println("getClassesFromProperties - requesting className: "+className); // Try to read the predefined classes from the props file. String typeOptions = EvAClient.getProperty(className); if (typeOptions == null) { // If none are defined, all assignable classes are searched the hard way, using the ReflectPackage return getClassesFromClassPath(className); } else { StringTokenizer st = new StringTokenizer(typeOptions, ", "); ArrayList classes = new ArrayList(); while (st.hasMoreTokens()) { String current = st.nextToken().trim(); //System.out.println("current ="+current); try { Class.forName(current); // test for instantiability classes.add(current); } catch (Exception ex) { System.err.println("Couldn't load class with name: " + current); System.err.println("ex:"+ex.getMessage()); ex.printStackTrace(); } } return classes; } } public static ArrayList getClassesFromClassPath(String className) { ArrayList classes = new ArrayList(); int dotIndex = className.lastIndexOf('.'); if (dotIndex <= 0) { System.err.println("warning: " + className + " is not a package!"); } else { String pckg = className.substring(0, className.lastIndexOf('.')); Class[] clsArr; try { clsArr = ReflectPackage.getAssignableClassesInPackage(pckg, Class.forName(className), true, true); } catch (ClassNotFoundException e) { e.printStackTrace(); clsArr = null; } if (clsArr == null) { System.out.println("Warning: No configuration property found in: " +EvAClient.EVA_PROPERTY_FILE + " "+"for "+className); classes.add(className); } else { for (Class class1 : clsArr) { int m = class1.getModifiers(); if (!Modifier.isAbstract(m) && !class1.isInterface()) { // dont take abstract classes or interfaces try { Class[] params = new Class[0]; class1.getConstructor(params); classes.add(class1.getName()); } catch (NoSuchMethodException e) { System.err.println("GOE warning: Class " + class1.getName() + " has no default constructor, skipping..."); } } } } } return classes; } /** * Hide or show the editable property of a class, this makes sense for classes * which are represented visually using the GenericObjectEditor. * Returns false, if an error occurs, else true. * An instance may call this statically on itself by means of this.getClass(). * Actually this only sets the hidden property of the java bean which is checked in the * wasModified method of PropertySheetPanel. * * @param cls class the property belongs to * @param property string name of the property * @param hide desired value to set, true for hidden, false for visible * @return false, if an error occurs, else true */ public static boolean setExpertProperty(Class cls, String property, boolean expertValue) { try { BeanInfo bi = Introspector.getBeanInfo(cls); PropertyDescriptor[] props = bi.getPropertyDescriptors(); for (int i=0; i