source: src/main/java/weka/gui/ensembleLibraryEditor/tree/PropertyNode.java @ 20

Last change on this file since 20 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 13.5 KB
Line 
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/*
18 *    PropertyNode.java
19 *    Copyright (C) 2006 Robert Jung
20 *
21 */
22
23package weka.gui.ensembleLibraryEditor.tree;
24
25import weka.gui.GenericObjectEditor;
26import weka.gui.ensembleLibraryEditor.AddModelsPanel;
27
28import java.beans.PropertyEditor;
29import java.util.Vector;
30
31import javax.swing.JOptionPane;
32import javax.swing.JRootPane;
33import javax.swing.JTree;
34import javax.swing.tree.DefaultMutableTreeNode;
35import javax.swing.tree.DefaultTreeModel;
36
37/**
38 * This node class represents individual parameters of generic objects
39 * (in practice this means classifiers).  So all direct children of a
40 * classifier or other generic objects in the tree are going to be
41 * property nodes.  Note that these nodes do not themselves have editors
42 * all editing in the user interface actaully happens in the child
43 * nodes of this class that it controls.  On top of creating these
44 * child nodes and initializing them with the correct editing
45 * configuration, this class is also responsible for obtaining all of
46 * the possible values from the child nodes.
47 * 
48 * @author  Robert Jung (mrbobjung@gmail.com)
49 * @version $Revision: 1.1 $
50 */
51public class PropertyNode 
52  extends DefaultMutableTreeNode {
53 
54  /** for serialization */
55  private static final long serialVersionUID = 8179038568780212829L;
56
57  /** this is a reference to the parent panel of the JTree which is
58   * needed to display correctly anchored JDialogs*/
59  private final AddModelsPanel m_ParentPanel;
60 
61  /** the name of the node to be displayed */
62  private String m_Name;
63 
64  /** the node's tip text*/
65  private String m_ToolTipText;
66 
67  /** The propertyEditor created for the node, this is very useful in
68   * figuring out exactly waht kind of child editor nodes to create */
69  private PropertyEditor m_PropertyEditor;
70 
71  /** a reference to the tree model is necessary to be able to add and
72   * remove nodes in the tree */
73  private DefaultTreeModel m_TreeModel;
74 
75  /** a reference to the tree */
76  private JTree m_Tree;
77 
78  /**
79   * The constructor initialiazes the member variables of this node,
80   * Note that the "value" of this generic object is stored as the treeNode
81   * user object. After the values are initialized the constructor calls
82   * the addEditorNodes to create all the child nodes necessary to allow
83   * users to specify ranges of parameter values meaningful for the
84   * parameter that this node represents.
85   *
86   * @param tree                the tree to use
87   * @param panel               the pabel
88   * @param name                the name
89   * @param toolTipText         the tooltip
90   * @param value               the actual value
91   * @param pe                  the property editor
92   */
93  public PropertyNode(JTree tree, AddModelsPanel panel, String name,
94      String toolTipText, Object value, PropertyEditor pe) {
95   
96    super(value);
97   
98    m_Tree = tree;
99    m_TreeModel = (DefaultTreeModel) m_Tree.getModel();
100    m_ParentPanel = panel;
101    m_Name = name;
102    m_ToolTipText = toolTipText;
103    m_PropertyEditor = pe;
104   
105    addEditorNodes(name, toolTipText);
106  }
107 
108  /**
109   * getter for the tooltip text
110   *
111   * @return tooltip text
112   */
113  public String getToolTipText() {
114    return m_ToolTipText;
115  }
116 
117  /**
118   * getter for the name to be displayed for this node
119   *
120   * @return            the name
121   */
122  public String getName() {
123    return m_Name;
124  }
125 
126  /**
127   * this returns the property editor that was provided for this object. This
128   * propertyEditor object is initially chosen inside of the GenericObjectNode
129   * updateTree() method if you are interested in where it comes from.
130   *
131   * @return the default editor for this node
132   */
133  public PropertyEditor getPropertyEditor() {
134    return m_PropertyEditor;
135  }
136 
137  /**
138   * returns a string representation
139   *
140   * @return            a string representation
141   */
142  public String toString() {
143    return getClass().getName() + "[" + getUserObject().toString() + "]";
144  }
145 
146  /**
147   * This method figures out what kind of parameter type this node
148   * represents and then creates the appropriate set of child nodes
149   * for editing.
150   *
151   * @param name        the name
152   * @param toolTipText the tooltip
153   */
154  public void addEditorNodes(String name, String toolTipText) {
155   
156    Object value = getUserObject();
157   
158    if (value instanceof Number) {
159     
160      NumberNode minNode = new NumberNode("min: ", (Number) value,
161          NumberNode.NOT_ITERATOR, false, toolTipText);
162     
163      m_TreeModel.insertNodeInto(minNode, this, 0);
164     
165      Number one = null;
166      try {
167        one = minNode.getOneValue();
168      } catch (NumberClassNotFoundException e) {
169        e.printStackTrace();
170      }
171     
172      NumberNode iteratorNode = new NumberNode("iterator: ", one,
173          NumberNode.PLUS_EQUAL, true, toolTipText);
174      m_TreeModel.insertNodeInto(iteratorNode, this, 1);
175     
176      NumberNode maxNode = new NumberNode("max: ", (Number) value,
177          NumberNode.NOT_ITERATOR, true, toolTipText);
178      m_TreeModel.insertNodeInto(maxNode, this, 2);
179     
180    } else if (m_PropertyEditor instanceof GenericObjectEditor) {
181     
182      GenericObjectNode classifierNode = new GenericObjectNode(
183          m_ParentPanel, value,
184          (GenericObjectEditor) m_PropertyEditor, toolTipText);
185     
186      m_TreeModel.insertNodeInto(classifierNode, this, 0);
187      classifierNode.setTree(m_Tree);
188      classifierNode.updateTree();
189     
190    } else if (m_PropertyEditor.getTags() != null) {
191     
192      String selected = m_PropertyEditor.getAsText();
193      String tags[] = m_PropertyEditor.getTags();
194      if (tags != null)
195        for (int i = 0; i < tags.length; i++) {
196         
197          CheckBoxNode checkBoxNode = new CheckBoxNode(tags[i],
198              selected.equals(tags[i]), toolTipText);
199          m_TreeModel.insertNodeInto(checkBoxNode, this, i);
200         
201        }
202     
203    } else {
204     
205      DefaultNode defaultNode = new DefaultNode(name, toolTipText, value,
206          m_PropertyEditor);
207     
208      m_TreeModel.insertNodeInto(defaultNode, this, 0);
209     
210    }
211  }
212 
213  /**
214   * This method gets the range of values as specified by the
215   * child editor nodes.
216   *
217   * @return    all values
218   */
219  public Vector getAllValues() {
220   
221    Vector values = new Vector();
222   
223    //OK, there are four type of nodes that can branch off of a propertyNode
224   
225    DefaultMutableTreeNode child = (DefaultMutableTreeNode) m_TreeModel.getChild(this, 0);
226   
227    if (child instanceof GenericObjectNode) {
228      //Here we let the generic object class handles this for us
229      values = ((GenericObjectNode) child).getValues();
230     
231    } else if (child instanceof DefaultNode) {
232      //This is perhaps the easiest case.  GenericNodes are only responsible
233      //for a single value                             
234      values.add(((DefaultNode) child).getUserObject());
235     
236    } else if (child instanceof CheckBoxNode) {
237      //Iterate through all of the children add their
238      //value if they're selected
239     
240      int childCount = m_TreeModel.getChildCount(this);
241     
242      for (int i = 0; i < childCount; i++) {
243       
244        CheckBoxNode currentChild = (CheckBoxNode) m_TreeModel
245        .getChild(this, i);
246       
247        if (currentChild.getSelected())
248          values.add(currentChild.getUserObject());
249       
250      }
251     
252    } else if (child instanceof NumberNode) {
253      //here we need to handle some weird cases for inpout validation
254     
255      NumberNode minChild = (NumberNode) m_TreeModel.getChild(this, 0);
256      NumberNode iteratorChild = (NumberNode) m_TreeModel.getChild(this, 1);
257      NumberNode maxChild = (NumberNode) m_TreeModel.getChild(this, 2);
258     
259      boolean ignoreIterator = false;
260     
261      try {
262       
263        if (iteratorChild.getSelected()) {
264         
265          //first we check to see if the min value is greater than the max value
266          //if so then we gotta problem
267         
268          if (maxChild.lessThan(maxChild.getValue(), minChild.getValue())) {
269           
270            ignoreIterator = true;
271            throw new InvalidInputException(
272                "Invalid numeric input for node " + getName()
273                + ": min > max. ");
274          }
275         
276          //Make sure that the iterator value will actually "iterate" between the
277          //min and max values
278          if ((iteratorChild.getIteratorType() == NumberNode.PLUS_EQUAL)
279              && (iteratorChild.lessThan(
280                  iteratorChild.getValue(), iteratorChild
281                  .getZeroValue()) || (iteratorChild
282                      .equals(iteratorChild.getValue(),
283                          iteratorChild.getZeroValue())))) {
284           
285            ignoreIterator = true;
286            throw new InvalidInputException(
287                "Invalid numeric input for node " + getName()
288                + ": += iterator <= 0. ");
289           
290          } else if ((iteratorChild.getIteratorType() == NumberNode.TIMES_EQUAL)
291              && (iteratorChild.lessThan(
292                  iteratorChild.getValue(), iteratorChild
293                  .getOneValue()) || (iteratorChild
294                      .equals(iteratorChild.getValue(),
295                          iteratorChild.getOneValue())))) {
296           
297            ignoreIterator = true;
298            throw new InvalidInputException(
299                "Invalid numeric input for node " + getName()
300                + ": *= iterator <= 1. ");
301           
302          }
303         
304        }
305       
306      } catch (InvalidInputException e) {
307       
308        JRootPane parent = m_ParentPanel.getRootPane();
309       
310        JOptionPane.showMessageDialog(parent, "Invalid Input: "
311            + e.getMessage(), "Input error",
312            JOptionPane.ERROR_MESSAGE);
313       
314        e.printStackTrace();
315      } catch (NumberClassNotFoundException e) {
316        e.printStackTrace();
317      }
318     
319      if (!iteratorChild.getSelected() || ignoreIterator) {
320        //easiest case - if we don't care about the Iterator then we just throw
321        //in the min value along with the max value(if its selected) 
322        values.add(minChild.getUserObject());
323       
324        if (maxChild.getSelected()
325            && (!maxChild.getValue().equals(minChild.getValue())))
326          values.add(maxChild.getUserObject());
327       
328      } else {
329        //here we need to cycle through all of the values from min to max in
330        //increments specified by the inrement value.
331       
332        Number current = minChild.getValue();
333       
334        try {
335         
336          values.add(minChild.getValue());
337         
338          do {
339           
340            Number newNumber = null;
341           
342            if (iteratorChild.getIteratorType() == NumberNode.PLUS_EQUAL) {
343              newNumber = iteratorChild.addNumbers(iteratorChild.getValue(), current);
344            } else if (iteratorChild.getIteratorType() == NumberNode.TIMES_EQUAL) {
345              newNumber = iteratorChild.multiplyNumbers(
346                  iteratorChild.getValue(), current);
347            }
348           
349            current = newNumber;
350           
351            if (iteratorChild
352                .lessThan(current, maxChild.getValue())
353                && (!iteratorChild.equals(current, maxChild.getValue()))) {
354              values.add(newNumber);
355            }
356           
357          } while (iteratorChild.lessThan(current, maxChild.getValue())
358              && (!iteratorChild.equals(current, maxChild.getValue())));
359         
360          if (maxChild.getSelected()
361              && (!maxChild.getValue().equals(minChild.getValue())))
362            values.add(maxChild.getUserObject());
363         
364        } catch (Exception e) {
365          e.printStackTrace();
366        }
367       
368      }
369    }
370   
371    return values;
372  }
373 
374  /**
375   * This method informs a child number node whether or not it is
376   * allowed to be selected. NumberNodes are the only ones that need
377   * to ask permission first.  This simply makes sure that iterator
378   * nodes can't be selected when the max node is not selected.
379   *
380   * @param node        the node to check
381   * @return            true of the node can be selected
382   */
383  public boolean canSelect(NumberNode node) {
384   
385    boolean permission = true;
386   
387    NumberNode iteratorChild = (NumberNode) m_TreeModel.getChild(this, 1);
388    NumberNode maxChild = (NumberNode) m_TreeModel.getChild(this, 2);
389   
390    //the one case where we want to say no: you can not have an iterator
391    //without a maximum value
392    if (node == iteratorChild && (maxChild.getSelected() == false))
393      permission = false;
394   
395    return permission;
396  }
397 
398  /**
399   * informs a requesting child node whether or not it has permission
400   * to be deselected. Note that only NumberNodes and CheckBoxNodes
401   * are the only one's that have any notion of being deselected and
402   * therefore should be the only one's calling this method.
403   *
404   * @param node        the node to check
405   * @return            true if it can be de-selected
406   */
407  public boolean canDeselect(DefaultMutableTreeNode node) {
408   
409    boolean permission = true;
410   
411    if (node instanceof NumberNode) {
412     
413      NumberNode iteratorChild = (NumberNode) m_TreeModel.getChild(this,
414          1);
415      NumberNode maxChild = (NumberNode) m_TreeModel.getChild(this, 2);
416      //the one case where we want to say no for number nodes: you can
417      //not have an iterator without a maximum value
418      if (node == maxChild && (iteratorChild.getSelected() == true))
419        permission = false;
420     
421    } else if (node instanceof CheckBoxNode) {
422     
423      //For check box nodes, we only want to say no if there's only one
424      //box currently selected - because at least one box needs to be
425      //checked.
426      int totalSelected = 0;
427      int childCount = m_TreeModel.getChildCount(this);
428     
429      for (int i = 0; i < childCount; i++) {
430       
431        CheckBoxNode currentChild = (CheckBoxNode) m_TreeModel
432        .getChild(this, i);
433       
434        if (currentChild.getSelected())
435          totalSelected++;
436       
437      }
438     
439      if (totalSelected == 1)
440        permission = false;
441     
442    }
443   
444    return permission;
445  }
446}
Note: See TracBrowser for help on using the repository browser.