📄 genericobjectnode.java
字号:
/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* * GenericObjectNode.java * Copyright (C) 2006 Robert Jung * */package weka.gui.ensembleLibraryEditor.tree;import weka.classifiers.Classifier;import weka.gui.GenericObjectEditor;import weka.gui.ensembleLibraryEditor.AddModelsPanel;import java.awt.Component;import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.MethodDescriptor;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import java.beans.PropertyDescriptor;import java.beans.PropertyEditor;import java.beans.PropertyEditorManager;import java.beans.PropertyVetoException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Vector;import javax.swing.JFrame;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JTree;import javax.swing.tree.DefaultMutableTreeNode;import javax.swing.tree.DefaultTreeModel;/** * This class is responsible for allowing users to choose an object that * was provided with a GenericObjectEditor. Just about every one of these * Objects is a Weka Classifier. There are two important things that these * nodes are responsible for beyond the other parameter node types. First, * they must discover all of the parameters that need to be added in the * model as child nodes. This is done through a loop of introspection that * was copied and adapted from the weka.gui.PropertySheetPanel class. * Second, this class is also responsible for discovering all possible * combinations of GenericObject parameters that are stored in its child * nodes. This is accomplished by first discovering all of the child node * parameters in the getValues method and then finding all combinations of * these values with the combinAllValues method. * * @author Robert Jung (mrbobjung@gmail.com) * @version $Revision: 1.1 $ */public class GenericObjectNode extends DefaultMutableTreeNode implements PropertyChangeListener { /** for serialization */ private static final long serialVersionUID = 688096727663132485L; //The following 8 arrays hold the accumulated information about the //Classifier parameters that we discover through introspection. This //is very similar to the approach within PropertySheetPanel. /** Holds properties of the target */ private PropertyDescriptor m_Properties[]; /** this tracks which indexes of the m_Properties */ private Vector m_UsedPropertyIndexes; /** Holds the methods of the target */ private MethodDescriptor m_Methods[]; /** Holds property editors of the object */ private PropertyEditor m_Editors[]; /** Holds current object values for each property */ private Object m_Values[]; /** The labels for each property */ private String m_Names[]; /** The tool tip text for each property */ private String m_TipTexts[]; /** StringBuffer containing help text for the object being edited */ private StringBuffer m_HelpText; /** the GenericObjectEditor that was supplied for this node */ private GenericObjectEditor m_GenericObjectEditor; /** this Vector stores all of the possible combinations of parameters * that it obtains from its child nodes. These combinations are * created by the recursive combineAllValues method*/ private Vector m_WorkingSetCombinations; /** the tip text for our node editor to display */ private String m_ToolTipText; /** a reference to the tree model is necessary to be able to add and * remove nodes in the tree */ private DefaultTreeModel m_TreeModel; /** this is a reference to the Tree object that this node is * contained within. Its required for this node to be able to * add/remove nodes from the JTree*/ private JTree m_Tree; /** This is a reference to the parent panel of the JTree so that we can * supply it as the required argument when supplying warning JDialog * messages*/ private final AddModelsPanel m_ParentPanel; /** * The constructor initialiazes the member variables of this node, * Note that the "value" of this generic object is stored as the treeNode * user object. * * @param panel the reference to the parent panel for calls to JDialog * @param value the value stored at this tree node * @param genericObjectEditor the GenericObjectEditor for this object * @param toolTipText the tipText to be displayed for this object */ public GenericObjectNode(AddModelsPanel panel, Object value, GenericObjectEditor genericObjectEditor, String toolTipText) { super(value); //setObject(value); m_ParentPanel = panel; this.m_GenericObjectEditor = genericObjectEditor; this.m_ToolTipText = toolTipText; } /** * It seems kind of dumb that the reference to the tree model is passed in * seperately - but know that this is actually necessary. There is a really * weird chicken before the egg problem. You cannot create a TreeModel without * giving it its root node. However, the nodes in your tree can't update the * structure of the tree unless they have a reference to the TreeModel. So in * the end this was the only compromise that I could get to work well * * @param tree the tree to use */ public void setTree(JTree tree) { this.m_Tree = tree; this.m_TreeModel = (DefaultTreeModel) m_Tree.getModel(); } /** * returns the current tree * * @return the current tree */ public JTree getTree() { return m_Tree; } /** * A getter for the GenericObjectEditor for this node * * @return the editor */ public GenericObjectEditor getEditor() { return m_GenericObjectEditor; } /** * getter for the tooltip text * * @return tooltip text */ public StringBuffer getHelpText() { return m_HelpText; } /** * getter for the tooltip text * * @return tooltip text */ public String getToolTipText() { return m_ToolTipText; } /** * getter for this node's object * * @return the node's object */ public Object getObject() { return getUserObject(); } /** * setter for this nodes object * * @param newValue sets the new object */ public void setObject(Object newValue) { setUserObject(newValue); } /** * this is a simple filter for the setUserObject method. We basically * don't want null values to be passed in. * * @param o the object to set */ public void setUserObject(Object o) { if (o != null) super.setUserObject(o); } /** * getter for the parent panel * * @return the parent panel */ public JPanel getParentPanel() { return m_ParentPanel; } /** * returns always null * * @return always null */ public String toString() { return null; //return getClass().getName() + "[" + getUserObject().toString() + "]"; } /** * This implements the PropertyChangeListener for this node that gets * registered with its Editor. All we really have to do is change the * Object value stored internally at this node when its editor says the * value changed. * * @param evt the event */ public void propertyChange(PropertyChangeEvent evt) { Object newValue = ((GenericObjectEditor) evt.getSource()).getValue(); if (!newValue.getClass().equals(getObject().getClass())) { if (m_TreeModel.getRoot() == this) { try { m_ParentPanel.buildClassifierTree((Classifier) newValue .getClass().newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } m_ParentPanel.update(m_ParentPanel.getGraphics()); m_ParentPanel.repaint(); //System.out.println("Changed root"); } else { setObject(newValue); updateTree(); updateTree(); m_TreeModel.nodeChanged(this); } } } /** * This method uses introspection to programatically discover all of * the parameters for this generic object. For each one of them it * uses the TreeModel reference to create a new subtree to represent * that parameter and its value ranges. Note that all of these nodes * are PropertyNodes which themselves hold the logic of figuring out * what type of parameter it is they are representing and thus what * type of subtree to build. * <p/> * We need to be careful because this was molded from the code inside of * the PropertySheetPanel class. Which means that we are wide open * to copy/paste problems. In the future, when that code changes to * adapt to other changes in Weka then this could easily become broken. */ public void updateTree() { int childCount = m_TreeModel.getChildCount(this); for (int i = 0; i < childCount; i++) { DefaultMutableTreeNode child = (DefaultMutableTreeNode) m_TreeModel.getChild(this, 0); m_TreeModel.removeNodeFromParent(child); } //removeAllChildren(); Object classifier = this.getUserObject(); try { BeanInfo bi = Introspector.getBeanInfo(classifier.getClass()); m_Properties = bi.getPropertyDescriptors(); m_Methods = bi.getMethodDescriptors(); } catch (IntrospectionException ex) { System.err.println("PropertySheet: Couldn't introspect"); return; } // Look for a globalInfo method that returns a string // describing the target for (int i = 0; i < m_Methods.length; i++) { String name = m_Methods[i].getDisplayName(); Method meth = m_Methods[i].getMethod(); if (name.equals("globalInfo")) { if (meth.getReturnType().equals(String.class)) { try { Object args[] = {}; String globalInfo = (String) (meth.invoke(getObject(), args)); String summary = globalInfo; int ci = globalInfo.indexOf('.'); if (ci != -1) { summary = globalInfo.substring(0, ci + 1); } final String className = getObject().getClass().getName(); m_HelpText = new StringBuffer("NAME\n"); m_HelpText.append(className).append("\n\n"); m_HelpText.append("SYNOPSIS\n").append(globalInfo).append("\n\n"); } catch (Exception ex) { // ignored }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -