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.
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.
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.
19
* Copyright (C) 2006 Robert Jung
23
package weka.gui.ensembleLibraryEditor.tree;
25
import weka.gui.GenericObjectEditor;
26
import weka.gui.ensembleLibraryEditor.AddModelsPanel;
28
import java.beans.PropertyEditor;
29
import java.util.Vector;
31
import javax.swing.JOptionPane;
32
import javax.swing.JRootPane;
33
import javax.swing.JTree;
34
import javax.swing.tree.DefaultMutableTreeNode;
35
import javax.swing.tree.DefaultTreeModel;
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.
48
* @author Robert Jung (mrbobjung@gmail.com)
49
* @version $Revision: 1.1 $
51
public class PropertyNode
52
extends DefaultMutableTreeNode {
54
/** for serialization */
55
private static final long serialVersionUID = 8179038568780212829L;
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;
61
/** the name of the node to be displayed */
62
private String m_Name;
64
/** the node's tip text*/
65
private String m_ToolTipText;
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;
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;
75
/** a reference to the tree */
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.
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
93
public PropertyNode(JTree tree, AddModelsPanel panel, String name,
94
String toolTipText, Object value, PropertyEditor pe) {
99
m_TreeModel = (DefaultTreeModel) m_Tree.getModel();
100
m_ParentPanel = panel;
102
m_ToolTipText = toolTipText;
103
m_PropertyEditor = pe;
105
addEditorNodes(name, toolTipText);
109
* getter for the tooltip text
111
* @return tooltip text
113
public String getToolTipText() {
114
return m_ToolTipText;
118
* getter for the name to be displayed for this node
122
public String getName() {
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.
131
* @return the default editor for this node
133
public PropertyEditor getPropertyEditor() {
134
return m_PropertyEditor;
138
* returns a string representation
140
* @return a string representation
142
public String toString() {
143
return getClass().getName() + "[" + getUserObject().toString() + "]";
147
* This method figures out what kind of parameter type this node
148
* represents and then creates the appropriate set of child nodes
151
* @param name the name
152
* @param toolTipText the tooltip
154
public void addEditorNodes(String name, String toolTipText) {
156
Object value = getUserObject();
158
if (value instanceof Number) {
160
NumberNode minNode = new NumberNode("min: ", (Number) value,
161
NumberNode.NOT_ITERATOR, false, toolTipText);
163
m_TreeModel.insertNodeInto(minNode, this, 0);
167
one = minNode.getOneValue();
168
} catch (NumberClassNotFoundException e) {
172
NumberNode iteratorNode = new NumberNode("iterator: ", one,
173
NumberNode.PLUS_EQUAL, true, toolTipText);
174
m_TreeModel.insertNodeInto(iteratorNode, this, 1);
176
NumberNode maxNode = new NumberNode("max: ", (Number) value,
177
NumberNode.NOT_ITERATOR, true, toolTipText);
178
m_TreeModel.insertNodeInto(maxNode, this, 2);
180
} else if (m_PropertyEditor instanceof GenericObjectEditor) {
182
GenericObjectNode classifierNode = new GenericObjectNode(
183
m_ParentPanel, value,
184
(GenericObjectEditor) m_PropertyEditor, toolTipText);
186
m_TreeModel.insertNodeInto(classifierNode, this, 0);
187
classifierNode.setTree(m_Tree);
188
classifierNode.updateTree();
190
} else if (m_PropertyEditor.getTags() != null) {
192
String selected = m_PropertyEditor.getAsText();
193
String tags[] = m_PropertyEditor.getTags();
195
for (int i = 0; i < tags.length; i++) {
197
CheckBoxNode checkBoxNode = new CheckBoxNode(tags[i],
198
selected.equals(tags[i]), toolTipText);
199
m_TreeModel.insertNodeInto(checkBoxNode, this, i);
205
DefaultNode defaultNode = new DefaultNode(name, toolTipText, value,
208
m_TreeModel.insertNodeInto(defaultNode, this, 0);
214
* This method gets the range of values as specified by the
215
* child editor nodes.
219
public Vector getAllValues() {
221
Vector values = new Vector();
223
//OK, there are four type of nodes that can branch off of a propertyNode
225
DefaultMutableTreeNode child = (DefaultMutableTreeNode) m_TreeModel.getChild(this, 0);
227
if (child instanceof GenericObjectNode) {
228
//Here we let the generic object class handles this for us
229
values = ((GenericObjectNode) child).getValues();
231
} else if (child instanceof DefaultNode) {
232
//This is perhaps the easiest case. GenericNodes are only responsible
234
values.add(((DefaultNode) child).getUserObject());
236
} else if (child instanceof CheckBoxNode) {
237
//Iterate through all of the children add their
238
//value if they're selected
240
int childCount = m_TreeModel.getChildCount(this);
242
for (int i = 0; i < childCount; i++) {
244
CheckBoxNode currentChild = (CheckBoxNode) m_TreeModel
247
if (currentChild.getSelected())
248
values.add(currentChild.getUserObject());
252
} else if (child instanceof NumberNode) {
253
//here we need to handle some weird cases for inpout validation
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);
259
boolean ignoreIterator = false;
263
if (iteratorChild.getSelected()) {
265
//first we check to see if the min value is greater than the max value
266
//if so then we gotta problem
268
if (maxChild.lessThan(maxChild.getValue(), minChild.getValue())) {
270
ignoreIterator = true;
271
throw new InvalidInputException(
272
"Invalid numeric input for node " + getName()
276
//Make sure that the iterator value will actually "iterate" between the
278
if ((iteratorChild.getIteratorType() == NumberNode.PLUS_EQUAL)
279
&& (iteratorChild.lessThan(
280
iteratorChild.getValue(), iteratorChild
281
.getZeroValue()) || (iteratorChild
282
.equals(iteratorChild.getValue(),
283
iteratorChild.getZeroValue())))) {
285
ignoreIterator = true;
286
throw new InvalidInputException(
287
"Invalid numeric input for node " + getName()
288
+ ": += iterator <= 0. ");
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())))) {
297
ignoreIterator = true;
298
throw new InvalidInputException(
299
"Invalid numeric input for node " + getName()
300
+ ": *= iterator <= 1. ");
306
} catch (InvalidInputException e) {
308
JRootPane parent = m_ParentPanel.getRootPane();
310
JOptionPane.showMessageDialog(parent, "Invalid Input: "
311
+ e.getMessage(), "Input error",
312
JOptionPane.ERROR_MESSAGE);
315
} catch (NumberClassNotFoundException e) {
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());
324
if (maxChild.getSelected()
325
&& (!maxChild.getValue().equals(minChild.getValue())))
326
values.add(maxChild.getUserObject());
329
//here we need to cycle through all of the values from min to max in
330
//increments specified by the inrement value.
332
Number current = minChild.getValue();
336
values.add(minChild.getValue());
340
Number newNumber = null;
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);
352
.lessThan(current, maxChild.getValue())
353
&& (!iteratorChild.equals(current, maxChild.getValue()))) {
354
values.add(newNumber);
357
} while (iteratorChild.lessThan(current, maxChild.getValue())
358
&& (!iteratorChild.equals(current, maxChild.getValue())));
360
if (maxChild.getSelected()
361
&& (!maxChild.getValue().equals(minChild.getValue())))
362
values.add(maxChild.getUserObject());
364
} catch (Exception e) {
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.
380
* @param node the node to check
381
* @return true of the node can be selected
383
public boolean canSelect(NumberNode node) {
385
boolean permission = true;
387
NumberNode iteratorChild = (NumberNode) m_TreeModel.getChild(this, 1);
388
NumberNode maxChild = (NumberNode) m_TreeModel.getChild(this, 2);
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))
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.
404
* @param node the node to check
405
* @return true if it can be de-selected
407
public boolean canDeselect(DefaultMutableTreeNode node) {
409
boolean permission = true;
411
if (node instanceof NumberNode) {
413
NumberNode iteratorChild = (NumberNode) m_TreeModel.getChild(this,
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))
421
} else if (node instanceof CheckBoxNode) {
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
426
int totalSelected = 0;
427
int childCount = m_TreeModel.getChildCount(this);
429
for (int i = 0; i < childCount; i++) {
431
CheckBoxNode currentChild = (CheckBoxNode) m_TreeModel
434
if (currentChild.getSelected())
439
if (totalSelected == 1)
b'\\ No newline at end of file'