GenericArrayEditor.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 15k
Category:

Windows Develop

Development Platform:

Java

  1. /*
  2.  *    This program is free software; you can redistribute it and/or modify
  3.  *    it under the terms of the GNU General Public License as published by
  4.  *    the Free Software Foundation; either version 2 of the License, or
  5.  *    (at your option) any later version.
  6.  *
  7.  *    This program is distributed in the hope that it will be useful,
  8.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *    GNU General Public License for more details.
  11.  *
  12.  *    You should have received a copy of the GNU General Public License
  13.  *    along with this program; if not, write to the Free Software
  14.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  */
  16. /*
  17.  *    GenericArrayEditor.java
  18.  *    Copyright (C) 1999 Len Trigg
  19.  *
  20.  */
  21. package weka.gui;
  22. import weka.core.SelectedTag;
  23. import weka.core.SerializedObject;
  24. import weka.classifiers.Classifier;
  25. import java.lang.reflect.Array;
  26. import java.beans.PropertyChangeEvent;
  27. import java.beans.PropertyChangeSupport;
  28. import java.beans.PropertyChangeListener;
  29. import java.beans.PropertyEditor;
  30. import java.beans.PropertyEditorManager;
  31. import java.awt.Graphics;
  32. import java.awt.Insets;
  33. import java.awt.Rectangle;
  34. import java.awt.Font;
  35. import java.awt.Component;
  36. import java.awt.Dimension;
  37. import java.awt.BorderLayout;
  38. import java.awt.FontMetrics;
  39. import java.awt.FlowLayout;
  40. import java.awt.event.ItemListener;
  41. import java.awt.event.ActionEvent;
  42. import java.awt.event.ActionListener;
  43. import java.awt.event.ItemEvent;
  44. import java.awt.event.WindowAdapter;
  45. import java.awt.event.WindowEvent;
  46. import javax.swing.JLabel;
  47. import javax.swing.JButton;
  48. import javax.swing.ListCellRenderer;
  49. import javax.swing.DefaultListCellRenderer;
  50. import javax.swing.JPanel;
  51. import javax.swing.JList;
  52. import javax.swing.ListModel;
  53. import javax.swing.DefaultListModel;
  54. import javax.swing.JScrollPane;
  55. import javax.swing.SwingConstants;
  56. import javax.swing.event.ListSelectionListener;
  57. import javax.swing.event.ListSelectionEvent;
  58. import javax.swing.JOptionPane;
  59. /** 
  60.  * A PropertyEditor for arrays of objects that themselves have
  61.  * property editors.
  62.  *
  63.  * @author Len Trigg (trigg@cs.waikato.ac.nz)
  64.  * @version $Revision: 1.11 $
  65.  */
  66. public class GenericArrayEditor extends JPanel
  67.   implements PropertyEditor {
  68.   /** Handles property change notification */
  69.   private PropertyChangeSupport m_Support = new PropertyChangeSupport(this);
  70.   /** The label for when we can't edit that type */
  71.   private JLabel m_Label = new JLabel("Can't edit", SwingConstants.CENTER);
  72.   
  73.   /** The list component displaying current values */
  74.   private JList m_ElementList = new JList();
  75.   /** The class of objects allowed in the array */
  76.   private Class m_ElementClass = String.class;
  77.   /** The defaultlistmodel holding our data */
  78.   private DefaultListModel m_ListModel;
  79.   /** The property editor for the class we are editing */
  80.   private PropertyEditor m_ElementEditor;
  81.   /** Click this to delete the selected array values */
  82.   private JButton m_DeleteBut = new JButton("Delete");
  83.   /** Click to add the current object configuration to the array */
  84.   private JButton m_AddBut = new JButton("Add");
  85.   /** Listens to buttons being pressed and taking the appropriate action */
  86.   private ActionListener m_InnerActionListener =
  87.     new ActionListener() {
  88.     public void actionPerformed(ActionEvent e) {
  89.       if (e.getSource() == m_DeleteBut) {
  90. int [] selected = m_ElementList.getSelectedIndices();
  91. if (selected != null) {
  92.   for (int i = 0; i < selected.length; i++) {
  93.     int current = selected[i];
  94.     m_ListModel.removeElementAt(current);
  95.     if (m_ListModel.size() > current) {
  96.       m_ElementList.setSelectedIndex(current);
  97.     }
  98.   }
  99.   m_Support.firePropertyChange("", null, null);
  100. }
  101. if (m_ElementList.getSelectedIndex() == -1) {
  102.   m_DeleteBut.setEnabled(false);
  103. }
  104.       } else if (e.getSource() == m_AddBut) {
  105. int selected = m_ElementList.getSelectedIndex();
  106. Object addObj = m_ElementEditor.getValue();
  107. // Make a full copy of the object using serialization
  108. try {
  109.           SerializedObject so = new SerializedObject(addObj);
  110.   addObj = so.getObject();
  111.   if (selected != -1) {
  112.     m_ListModel.insertElementAt(addObj, selected);
  113.   } else {
  114.     m_ListModel.addElement(addObj);
  115.   }
  116.   m_Support.firePropertyChange("", null, null);
  117. } catch (Exception ex) {
  118.   JOptionPane.showMessageDialog(GenericArrayEditor.this,
  119. "Could not create an object copy",
  120. null,
  121. JOptionPane.ERROR_MESSAGE);
  122. }
  123.       } 
  124.     }
  125.   };
  126.   /** Listens to list items being selected and takes appropriate action */
  127.   private ListSelectionListener m_InnerSelectionListener =
  128.     new ListSelectionListener() {
  129.       public void valueChanged(ListSelectionEvent e) {
  130. if (e.getSource() == m_ElementList) {
  131.   // Enable the delete button
  132.   if (m_ElementList.getSelectedIndex() != -1) {
  133.     m_DeleteBut.setEnabled(true);
  134.   }
  135. }
  136.       }
  137.   };
  138.     
  139.   /**
  140.    * Sets up the array editor.
  141.    */
  142.   public GenericArrayEditor() {
  143.     setLayout(new BorderLayout());
  144.     add(m_Label, BorderLayout.CENTER);
  145.     m_DeleteBut.addActionListener(m_InnerActionListener);
  146.     m_AddBut.addActionListener(m_InnerActionListener);
  147.     m_ElementList.addListSelectionListener(m_InnerSelectionListener);
  148.     m_AddBut.setToolTipText("Add the current item to the list");
  149.     m_DeleteBut.setToolTipText("Delete the selected list item");
  150.   }
  151.   /* This class handles the creation of list cell renderers from the 
  152.    * property editors.
  153.    */
  154.   private class EditorListCellRenderer implements ListCellRenderer {
  155.     /** The class of the property editor for array objects */
  156.     private Class m_EditorClass;
  157.     /** The class of the array values */
  158.     private Class m_ValueClass;
  159.     /**
  160.      * Creates the list cell renderer.
  161.      *
  162.      * @param editorClass The class of the property editor for array objects
  163.      * @param valueClass The class of the array values
  164.      */
  165.     public EditorListCellRenderer(Class editorClass, Class valueClass) {
  166.       m_EditorClass = editorClass;
  167.       m_ValueClass = valueClass;
  168.     }
  169.     /**
  170.      * Creates a cell rendering component.
  171.      *
  172.      * @param JList the list that will be rendered in
  173.      * @param Object the cell value
  174.      * @param int which element of the list to render
  175.      * @param boolean true if the cell is selected
  176.      * @param boolean true if the cell has the focus
  177.      * @return the rendering component
  178.      */
  179.     public Component getListCellRendererComponent(final JList list,
  180.   final Object value,
  181.   final int index,
  182.   final boolean isSelected,
  183.   final boolean cellHasFocus) {
  184.       try {
  185. final PropertyEditor e = (PropertyEditor)m_EditorClass.newInstance();
  186. if (e instanceof GenericObjectEditor) {
  187.   //   ((GenericObjectEditor) e).setDisplayOnly(true);
  188.   ((GenericObjectEditor) e).setClassType(m_ValueClass);
  189. }
  190. e.setValue(value);
  191. return new JPanel() {
  192.   public void paintComponent(Graphics g) {
  193.     Insets i = this.getInsets();
  194.     Rectangle box = new Rectangle(i.left, i.top,
  195.   this.getWidth() - i.right,
  196.   this.getHeight() - i.bottom );
  197.     g.setColor(isSelected
  198.        ? list.getSelectionBackground()
  199.        : list.getBackground());
  200.     g.fillRect(0, 0, this.getWidth(), this.getHeight());
  201.     g.setColor(isSelected
  202.        ? list.getSelectionForeground()
  203.        : list.getForeground());
  204.     e.paintValue(g, box);
  205.   }
  206.   
  207.   public Dimension getPreferredSize() {
  208.     Font f = this.getFont();
  209.     FontMetrics fm = this.getFontMetrics(f);
  210.     return new Dimension(0, fm.getHeight());
  211.   }
  212. };
  213.       } catch (Exception ex) {
  214. return null;
  215.       }
  216.     }
  217.   }
  218.   /**
  219.    * Updates the type of object being edited, so attempts to find an
  220.    * appropriate propertyeditor.
  221.    *
  222.    * @param o a value of type 'Object'
  223.    */
  224.   private void updateEditorType(Object o) {
  225.     // Determine if the current object is an array
  226.     m_ElementEditor = null; m_ListModel = null;
  227.     removeAll();
  228.     if ((o != null) && (o.getClass().isArray())) {
  229.       Class elementClass = o.getClass().getComponentType();    
  230.       PropertyEditor editor = PropertyEditorManager.findEditor(elementClass);
  231.       Component view = null;
  232.       ListCellRenderer lcr = new DefaultListCellRenderer();
  233.       if (editor != null) {
  234. if (editor instanceof GenericObjectEditor) {
  235.   ((GenericObjectEditor) editor).setClassType(elementClass);
  236. }
  237. if (editor.isPaintable() && editor.supportsCustomEditor()) {
  238.   view = new PropertyPanel(editor);
  239.   lcr = new EditorListCellRenderer(editor.getClass(), elementClass);
  240. } else if (editor.getTags() != null) {
  241.   view = new PropertyValueSelector(editor);
  242. } else if (editor.getAsText() != null) {
  243.   view = new PropertyText(editor);
  244. }
  245.       }
  246.       if (view == null) {
  247. System.err.println("No property editor for class: "
  248.    + elementClass.getName());
  249.       } else {
  250. m_ElementEditor = editor;
  251. // Create the ListModel and populate it
  252. m_ListModel = new DefaultListModel();
  253. m_ElementClass = elementClass;
  254. for (int i = 0; i < Array.getLength(o); i++) {
  255.   m_ListModel.addElement(Array.get(o,i));
  256. }
  257. m_ElementList.setCellRenderer(lcr);
  258. m_ElementList.setModel(m_ListModel);
  259. if (m_ListModel.getSize() > 0) {
  260.   m_ElementList.setSelectedIndex(0);
  261.   m_DeleteBut.setEnabled(true);
  262. } else {
  263.   m_DeleteBut.setEnabled(false);
  264. }
  265. try {
  266.   if (m_ListModel.getSize() > 0) {
  267.     m_ElementEditor.setValue(m_ListModel.getElementAt(0));
  268.   } else {
  269.     if (m_ElementEditor instanceof GenericObjectEditor) {
  270.       ((GenericObjectEditor)m_ElementEditor).setDefaultValue();
  271.     } else {
  272.       m_ElementEditor.setValue(m_ElementClass.newInstance());
  273.     }
  274.   }
  275.   
  276.   JPanel panel = new JPanel();
  277.   panel.setLayout(new BorderLayout());
  278.   panel.add(view, BorderLayout.CENTER);
  279.   panel.add(m_AddBut, BorderLayout.EAST);
  280.   add(panel, BorderLayout.NORTH);
  281.   add(new JScrollPane(m_ElementList), BorderLayout.CENTER);
  282.   add(m_DeleteBut, BorderLayout.SOUTH);
  283.   m_ElementEditor
  284.     .addPropertyChangeListener(new PropertyChangeListener() {
  285.     public void propertyChange(PropertyChangeEvent e) {
  286.       repaint();
  287.     }
  288.   });
  289. } catch (Exception ex) {
  290.   System.err.println(ex.getMessage());
  291.   m_ElementEditor = null;
  292. }
  293.       }
  294.     }
  295.     if (m_ElementEditor == null) {
  296.       add(m_Label, BorderLayout.CENTER);
  297.     }
  298.     m_Support.firePropertyChange("", null, null);
  299.     validate();
  300.   }
  301.   /**
  302.    * Sets the current object array.
  303.    *
  304.    * @param o an object that must be an array.
  305.    */
  306.   public void setValue(Object o) {
  307.     // Create a new list model, put it in the list and resize?
  308.     updateEditorType(o);
  309.   }
  310.   /**
  311.    * Gets the current object array.
  312.    *
  313.    * @return the current object array
  314.    */
  315.   public Object getValue() {
  316.     if (m_ListModel == null) {
  317.       return null;
  318.     }
  319.     // Convert the listmodel to an array of strings and return it.
  320.     int length = m_ListModel.getSize();
  321.     Object result = Array.newInstance(m_ElementClass, length);
  322.     for (int i = 0; i < length; i++) {
  323.       Array.set(result, i, m_ListModel.elementAt(i));
  324.     }
  325.     return result;
  326.   }
  327.   
  328.   /**
  329.    * Supposedly returns an initialization string to create a classifier
  330.    * identical to the current one, including it's state, but this doesn't
  331.    * appear possible given that the initialization string isn't supposed to
  332.    * contain multiple statements.
  333.    *
  334.    * @return the java source code initialisation string
  335.    */
  336.   public String getJavaInitializationString() {
  337.     return "null";
  338.   }
  339.   /**
  340.    * Returns true to indicate that we can paint a representation of the
  341.    * string array
  342.    *
  343.    * @return true
  344.    */
  345.   public boolean isPaintable() {
  346.     return true;
  347.   }
  348.   /**
  349.    * Paints a representation of the current classifier.
  350.    *
  351.    * @param gfx the graphics context to use
  352.    * @param box the area we are allowed to paint into
  353.    */
  354.   public void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box) {
  355.     FontMetrics fm = gfx.getFontMetrics();
  356.     int vpad = (box.height - fm.getAscent()) / 2;
  357.     String rep = m_ListModel.getSize() + " " + m_ElementClass.getName();
  358.     gfx.drawString(rep, 2, fm.getHeight() + vpad);
  359.   }
  360.   /**
  361.    * Returns null as we don't support getting/setting values as text.
  362.    *
  363.    * @return null
  364.    */
  365.   public String getAsText() {
  366.     return null;
  367.   }
  368.   /**
  369.    * Returns null as we don't support getting/setting values as text. 
  370.    *
  371.    * @param text the text value
  372.    * @exception IllegalArgumentException as we don't support
  373.    * getting/setting values as text.
  374.    */
  375.   public void setAsText(String text) throws IllegalArgumentException {
  376.     throw new IllegalArgumentException(text);
  377.   }
  378.   /**
  379.    * Returns null as we don't support getting values as tags.
  380.    *
  381.    * @return null
  382.    */
  383.   public String[] getTags() {
  384.     return null;
  385.   }
  386.   /**
  387.    * Returns true because we do support a custom editor.
  388.    *
  389.    * @return true
  390.    */
  391.   public boolean supportsCustomEditor() {
  392.     return true;
  393.   }
  394.   
  395.   /**
  396.    * Returns the array editing component.
  397.    *
  398.    * @return a value of type 'java.awt.Component'
  399.    */
  400.   public java.awt.Component getCustomEditor() {
  401.     return this;
  402.   }
  403.   /**
  404.    * Adds a PropertyChangeListener who will be notified of value changes.
  405.    *
  406.    * @param l a value of type 'PropertyChangeListener'
  407.    */
  408.   public void addPropertyChangeListener(PropertyChangeListener l) {
  409.     m_Support.addPropertyChangeListener(l);
  410.   }
  411.   /**
  412.    * Removes a PropertyChangeListener.
  413.    *
  414.    * @param l a value of type 'PropertyChangeListener'
  415.    */
  416.   public void removePropertyChangeListener(PropertyChangeListener l) {
  417.     m_Support.removePropertyChangeListener(l);
  418.   }
  419.   /**
  420.    * Tests out the array editor from the command line.
  421.    *
  422.    * @param args ignored
  423.    */
  424.   public static void main(String [] args) {
  425.     try {
  426.       System.err.println("---Registering Weka Editors---");
  427.       java.beans.PropertyEditorManager
  428. .registerEditor(Classifier.class,
  429. GenericObjectEditor.class);
  430.       java.beans.PropertyEditorManager
  431. .registerEditor(SelectedTag.class,
  432. SelectedTagEditor.class);
  433.       java.beans.PropertyEditorManager
  434. .registerEditor(weka.filters.Filter.class,
  435. GenericObjectEditor.class);
  436.       java.beans.PropertyEditorManager
  437. .registerEditor(String [].class,
  438. GenericArrayEditor.class);
  439.       final GenericArrayEditor ce = new GenericArrayEditor();
  440.       final weka.filters.Filter [] initial = new weka.filters.Filter [0];
  441. /*
  442.       {
  443. new weka.filters.AddFilter()
  444. };*/
  445.       /*
  446.       final String [] initial = {
  447. "Hello",
  448. "There",
  449. "Bob"
  450. };*/
  451.       PropertyDialog pd = new PropertyDialog(ce, 100, 100);
  452.       pd.setSize(200,200);
  453.       pd.addWindowListener(new WindowAdapter() {
  454. public void windowClosing(WindowEvent e) {
  455.   System.exit(0);
  456. }
  457.       });
  458.       ce.setValue(initial);
  459.       //ce.validate();
  460.     } catch (Exception ex) {
  461.       ex.printStackTrace();
  462.       System.err.println(ex.getMessage());
  463.     }
  464.   }
  465. }