source: src/main/java/weka/gui/ensembleLibraryEditor/tree/NumberNode.java @ 17

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

Import di weka.

File size: 14.0 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 *    NumberNode.java
19 *    Copyright (C) 2006 Robert Jung
20 *
21 */
22
23package weka.gui.ensembleLibraryEditor.tree;
24
25import java.math.BigDecimal;
26import java.text.NumberFormat;
27
28import javax.swing.tree.DefaultMutableTreeNode;
29
30/**
31 * This subclass is responsible for allowing users to specify either a minimum,
32 * maximum, or iterator value for Integer attributes. It stores a value that is
33 * of type java.lang.Number to accomodate the many different number types used
34 * by Weka classifiers.
35 *
36 * @author  Robert Jung (mrbobjung@gmail.com)
37 * @version $Revision: 1.1 $
38 */
39public class NumberNode
40  extends DefaultMutableTreeNode {
41 
42  /** for serialization */
43  private static final long serialVersionUID = -2505599954089243851L;
44
45  /** the enumerated value indicating a node is not an iterator */
46  public static final int NOT_ITERATOR = 0;
47 
48  /** the enumerated value indicating a node is a *= iterator */
49  public static final int TIMES_EQUAL = 1;
50 
51  /** the enumerated value indicating a node is a += iterator */
52  public static final int PLUS_EQUAL = 2;
53 
54  /** the name of the node to be displayed */
55  private String m_Name;
56 
57  /** the iterator type, NOT_ITERATOR, TIMES_EQUAL, or PLUS_EQUAL */
58  private int m_IteratorType;
59 
60  /** this stores whether or not this node should have a checkbox */
61  private boolean m_Checkable;
62 
63  /** this stores the node's selected state */
64  private boolean m_Selected;
65 
66  /** the node's tipText */
67  private String m_ToolTipText;
68 
69  /**
70   * This method rounds a double to the number of decimal places defined by
71   * scale
72   *
73   * @param a           the value to round
74   * @return            the rounded value
75   */
76  public static double roundDouble(double a) {
77    return new BigDecimal("" + a).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
78  }
79 
80  /**
81   * This method rounds a float to the number of decimal places defined by
82   * scale
83   *
84   * @param a           the value to round
85   * @return            the rounded value
86   */
87  public static float roundFloat(float a) {
88    return new BigDecimal("" + a).setScale(scale, BigDecimal.ROUND_HALF_UP).floatValue();
89  }
90 
91  /**
92   * this defines the number of decimal places we care about, we arbitrarily
93   * chose 7 thinking that anything beyond this is overkill
94   */
95  public static final int scale = 7;
96 
97  /**
98   * This is the maximum floating point value that we care about when testing
99   * for equality.
100   */
101  public static final double epsilon = 0.000001;
102 
103  /**
104   * The constructor simply initializes all of the member variables
105   *
106   * @param text                the name
107   * @param value               the actual value
108   * @param iteratorType        the iterator type
109   * @param checkable           true if it's checkable
110   * @param toolTipText         the tooltip to use
111   */
112  public NumberNode(String text, Number value, int iteratorType,
113      boolean checkable, String toolTipText) {
114   
115    this.m_Name = text;
116    setValue(value);
117    this.m_IteratorType = iteratorType;
118    this.m_Checkable = checkable;
119    this.m_Selected = false;
120    this.m_ToolTipText = toolTipText;
121  }
122 
123  /**
124   * getter for the node selected state
125   *
126   * @return whether or not this node is selected
127   */
128  public boolean getSelected() {
129    return m_Selected;
130  }
131 
132  /**
133   * setter for the node selected state
134   *
135   * @param newValue
136   *            the new selected state
137   */
138  public void setSelected(boolean newValue) {
139    m_Selected = newValue;
140  }
141 
142  /**
143   * getter for this node's object
144   *
145   * @return    the current value
146   */
147  public Number getValue() {
148    return (Number) getUserObject();
149  }
150 
151  /**
152   * setter for this nodes object
153   *
154   * @param newValue    the new value to use
155   */
156  public void setValue(Number newValue) {
157    userObject = newValue;
158  }
159 
160  /**
161   * getter for this node's iteratorType which will be one of the three
162   * enumerated values
163   *
164   * @return            the iterator type
165   */
166  public int getIteratorType() {
167    return m_IteratorType;
168  }
169 
170  /**
171   * setter for this nodes iteratorType which should be one of the three
172   * enumerated values
173   *
174   * @param newValue    the new iterator type to use
175   */
176  public void setIteratorType(int newValue) {
177    m_IteratorType = newValue;
178  }
179 
180  /**
181   * returns whether or not this node can be toggled on and off
182   *
183   * @return            true if it's checkable
184   */
185  public boolean getCheckable() {
186    return m_Checkable;
187  }
188 
189  /**
190   * returns the text to be displayed for this node
191   *
192   * @return            the name
193   */
194  public String getText() {
195    return m_Name;
196  }
197 
198  /**
199   * getter for the tooltip text
200   *
201   * @return tooltip text
202   */
203  public String getToolTipText() {
204    return m_ToolTipText;
205  }
206 
207  /**
208   * this is a simple filter for the setUserObject method. We basically don't
209   * want null values to be passed in.
210   *
211   * @param o           the user object
212   */
213  public void setUserObject(Object o) {
214    if (o != null)
215      super.setUserObject(o);
216  }
217 
218  /**
219   * returns a string representation
220   *
221   * @return            a string representation
222   */
223  public String toString() {
224    return getClass().getName() + "[" + m_Name + ": "
225    + getUserObject().toString() + "]";
226  }
227 
228  // *************** IMPORTANT!!! ***********************
229  // I could not figure out a graceful way to deal with this!
230  // we have a requirement here to add, multiply, and test for
231  // equality various subclasses of java.lang.number the
232  // following eight methods are extremely redundant and are
233  // a horrible example cutting/pasting. However, this
234  // is what I've ended up with and its very clunky looking.
235  // If anyone knows a better way to do this then please be my
236  // guest by all means!
237 
238  // I really can't beleive there's not some slick way of handling
239  // this stuff built into the language
240 
241  /**
242   * figures out the class of this node's object and returns a new instance of
243   * it initialized with the value of "0".
244   *
245   * @return                                    0 as object
246   * @throws NumberClassNotFoundException       if number class not supported
247   */
248  public Number getZeroValue() throws NumberClassNotFoundException {
249   
250    Number value = getValue();
251    Number zero = null;
252   
253    if (value instanceof Double)
254      zero = new Double(0.0);
255    else if (value instanceof Integer)
256      zero = new Integer(0);
257    else if (value instanceof Float)
258      zero = new Float(0.0);
259    else if (value instanceof Long)
260      zero = new Long(0);
261    else {
262      throw new NumberClassNotFoundException(value.getClass()
263          + " not currently supported.");
264    }
265   
266    return zero;
267  }
268 
269  /**
270   * figures out the class of this node's object and returns a new instance of
271   * it initialized with the value of "1".
272   *
273   * @return                                    1 as object
274   * @throws NumberClassNotFoundException       if number class not supported
275   */
276  public Number getOneValue() throws NumberClassNotFoundException {
277   
278    Number value = getValue();
279    Number one = null;
280   
281    if (value instanceof Double)
282      one = new Double(1.0);
283    else if (value instanceof Integer)
284      one = new Integer(1);
285    else if (value instanceof Float)
286      one = new Float(1.0);
287    else if (value instanceof Long)
288      one = new Long(1);
289    else {
290      throw new NumberClassNotFoundException(value.getClass()
291          + " not currently supported.");
292    }
293    return one;
294  }
295 
296  /**
297   * figures out the class of this node's object and returns a new instance of
298   * it initialized with the value of "2".
299   *
300   * @return                                    2 as object
301   * @throws NumberClassNotFoundException       if number class not supported
302   */
303  public Number getTwoValue() throws NumberClassNotFoundException {
304   
305    Number value = getValue();
306    Number two = null;
307   
308    if (value instanceof Double)
309      two = new Double(2.0);
310    else if (value instanceof Integer)
311      two = new Integer(2);
312    else if (value instanceof Float)
313      two = new Float(2.0);
314    else if (value instanceof Long)
315      two = new Long(2);
316    else {
317      throw new NumberClassNotFoundException(value.getClass()
318          + " not currently supported.");
319    }
320    return two;
321  }
322 
323  /**
324   * adds two objects that are instances of one of the child classes of
325   * java.lang.Number
326   *
327   * @param a   the first number
328   * @param b   the second number
329   * @return    the sum: a+b
330   * @throws NumberClassNotFoundException       if number class not supported
331   */
332  public Number addNumbers(Number a, Number b)
333    throws NumberClassNotFoundException {
334   
335    Number sum = null;
336   
337    if (a instanceof Double && b instanceof Double) {
338      sum = new Double(roundDouble(a.doubleValue() + b.doubleValue()));
339      // trimNumber(sum);
340     
341    } else if (a instanceof Integer && b instanceof Integer) {
342      sum = new Integer(a.intValue() + b.intValue());
343    } else if (a instanceof Float && b instanceof Float) {
344      sum = new Float(roundFloat(a.floatValue() + b.floatValue()));
345     
346      // trimNumber(sum);
347     
348    } else if (a instanceof Long && b instanceof Long) {
349      sum = new Long(a.longValue() + b.longValue());
350    } else {
351      throw new NumberClassNotFoundException(a.getClass() + " and "
352          + b.getClass() + " not currently supported.");
353    }
354    return sum;
355  }
356 
357  /**
358   * multiplies two objects that are instances of one of the child classes of
359   * java.lang.Number
360   *
361   * @param a   the first number
362   * @param b   the second number
363   * @return    the product: a*b
364   * @throws NumberClassNotFoundException       if number class not supported
365   */
366  public Number multiplyNumbers(Number a, Number b)
367    throws NumberClassNotFoundException {
368   
369    Number product = null;
370   
371    if (a instanceof Double && b instanceof Double) {
372      product = new Double(roundDouble(a.doubleValue() * b.doubleValue()));
373     
374    } else if (a instanceof Integer && b instanceof Integer) {
375      product = new Integer(a.intValue() * b.intValue());
376    } else if (a instanceof Float && b instanceof Float) {
377      product = new Float(roundFloat(a.floatValue() * b.floatValue()));
378     
379    } else if (a instanceof Long && b instanceof Long) {
380      product = new Long(a.longValue() * b.longValue());
381    } else {
382      throw new NumberClassNotFoundException(a.getClass() + " and "
383          + b.getClass() + " not currently supported.");
384    }
385    return product;
386  }
387 
388  /**
389   * tests if the first argument is greater than the second among two objects
390   * that are instances of one of the child classes of java.lang.Number
391   *
392   * @param a   the first number
393   * @param b   the second number
394   * @return    true if a is less than b
395   * @throws NumberClassNotFoundException       if number class not supported
396   */
397  public boolean lessThan(Number a, Number b)
398    throws NumberClassNotFoundException {
399   
400    boolean greater = false;
401   
402    if (a instanceof Double && b instanceof Double) {
403      if (a.doubleValue() < b.doubleValue())
404        greater = true;
405    } else if (a instanceof Integer && b instanceof Integer) {
406      if (a.intValue() < b.intValue())
407        greater = true;
408    } else if (a instanceof Float && b instanceof Float) {
409      if (a.floatValue() < b.floatValue())
410        greater = true;
411    } else if (a instanceof Long && b instanceof Long) {
412      if (a.longValue() < b.longValue())
413        greater = true;
414    } else {
415      throw new NumberClassNotFoundException(a.getClass() + " and "
416          + b.getClass() + " not currently supported.");
417    }
418   
419    return greater;
420   
421  }
422 
423  /**
424   * tests for equality among two objects that are instances of one of the
425   * child classes of java.lang.Number
426   *
427   * @param a   the first number
428   * @param b   the second number
429   * @return    true if the two values are equal
430   * @throws NumberClassNotFoundException       if number class not supported
431   */
432  public boolean equals(Number a, Number b)
433    throws NumberClassNotFoundException {
434   
435    boolean equals = false;
436   
437    if (a instanceof Double && b instanceof Double) {
438      if (Math.abs(a.doubleValue() - b.doubleValue()) < epsilon)
439        equals = true;
440    } else if (a instanceof Integer && b instanceof Integer) {
441      if (a.intValue() == b.intValue())
442        equals = true;
443    } else if (a instanceof Float && b instanceof Float) {
444      if (Math.abs(a.floatValue() - b.floatValue()) < epsilon)
445        equals = true;
446    } else if (a instanceof Long && b instanceof Long) {
447      if (a.longValue() == b.longValue())
448        equals = true;
449    } else {
450      throw new NumberClassNotFoundException(a.getClass() + " and "
451          + b.getClass() + " not currently supported.");
452    }
453   
454    return equals;
455  }
456 
457  /**
458   * A helper method to figure out what number format should be used to
459   * display the numbers value in a formatted text box.
460   *
461   * @return the number format
462   * @throws NumberClassNotFoundException       if number class not supported
463   */
464  public NumberFormat getNumberFormat() throws NumberClassNotFoundException {
465    NumberFormat numberFormat = null;
466   
467    Number value = getValue();
468   
469    if (value instanceof Double) {
470      numberFormat = NumberFormat.getInstance();
471      numberFormat.setMaximumFractionDigits(7);
472    } else if (value instanceof Integer) {
473      numberFormat = NumberFormat.getIntegerInstance();
474    } else if (value instanceof Float) {
475      numberFormat = NumberFormat.getInstance();
476      numberFormat.setMaximumFractionDigits(7);
477    } else if (value instanceof Long) {
478      numberFormat = NumberFormat.getIntegerInstance();
479    } else {
480      throw new NumberClassNotFoundException(value.getClass()
481          + " not currently supported.");
482    }
483   
484    return numberFormat;
485  }
486}
Note: See TracBrowser for help on using the repository browser.