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 | * GenericObjectNode.java |
---|
19 | * Copyright (C) 2006 Robert Jung |
---|
20 | * |
---|
21 | */ |
---|
22 | |
---|
23 | package weka.gui.ensembleLibraryEditor.tree; |
---|
24 | |
---|
25 | import weka.classifiers.Classifier; |
---|
26 | import weka.gui.GenericObjectEditor; |
---|
27 | import weka.gui.ensembleLibraryEditor.AddModelsPanel; |
---|
28 | |
---|
29 | import java.awt.Component; |
---|
30 | import java.beans.BeanInfo; |
---|
31 | import java.beans.IntrospectionException; |
---|
32 | import java.beans.Introspector; |
---|
33 | import java.beans.MethodDescriptor; |
---|
34 | import java.beans.PropertyChangeEvent; |
---|
35 | import java.beans.PropertyChangeListener; |
---|
36 | import java.beans.PropertyDescriptor; |
---|
37 | import java.beans.PropertyEditor; |
---|
38 | import java.beans.PropertyEditorManager; |
---|
39 | import java.beans.PropertyVetoException; |
---|
40 | import java.lang.reflect.InvocationTargetException; |
---|
41 | import java.lang.reflect.Method; |
---|
42 | import java.util.Vector; |
---|
43 | |
---|
44 | import javax.swing.JFrame; |
---|
45 | import javax.swing.JOptionPane; |
---|
46 | import javax.swing.JPanel; |
---|
47 | import javax.swing.JTree; |
---|
48 | import javax.swing.tree.DefaultMutableTreeNode; |
---|
49 | import javax.swing.tree.DefaultTreeModel; |
---|
50 | |
---|
51 | /** |
---|
52 | * This class is responsible for allowing users to choose an object that |
---|
53 | * was provided with a GenericObjectEditor. Just about every one of these |
---|
54 | * Objects is a Weka Classifier. There are two important things that these |
---|
55 | * nodes are responsible for beyond the other parameter node types. First, |
---|
56 | * they must discover all of the parameters that need to be added in the |
---|
57 | * model as child nodes. This is done through a loop of introspection that |
---|
58 | * was copied and adapted from the weka.gui.PropertySheetPanel class. |
---|
59 | * Second, this class is also responsible for discovering all possible |
---|
60 | * combinations of GenericObject parameters that are stored in its child |
---|
61 | * nodes. This is accomplished by first discovering all of the child node |
---|
62 | * parameters in the getValues method and then finding all combinations of |
---|
63 | * these values with the combinAllValues method. |
---|
64 | * |
---|
65 | * @author Robert Jung (mrbobjung@gmail.com) |
---|
66 | * @version $Revision: 1.1 $ |
---|
67 | */ |
---|
68 | public class GenericObjectNode |
---|
69 | extends DefaultMutableTreeNode |
---|
70 | implements PropertyChangeListener { |
---|
71 | |
---|
72 | /** for serialization */ |
---|
73 | private static final long serialVersionUID = 688096727663132485L; |
---|
74 | |
---|
75 | //The following 8 arrays hold the accumulated information about the |
---|
76 | //Classifier parameters that we discover through introspection. This |
---|
77 | //is very similar to the approach within PropertySheetPanel. |
---|
78 | |
---|
79 | /** Holds properties of the target */ |
---|
80 | private PropertyDescriptor m_Properties[]; |
---|
81 | |
---|
82 | /** this tracks which indexes of the m_Properties */ |
---|
83 | private Vector m_UsedPropertyIndexes; |
---|
84 | |
---|
85 | /** Holds the methods of the target */ |
---|
86 | private MethodDescriptor m_Methods[]; |
---|
87 | |
---|
88 | /** Holds property editors of the object */ |
---|
89 | private PropertyEditor m_Editors[]; |
---|
90 | |
---|
91 | /** Holds current object values for each property */ |
---|
92 | private Object m_Values[]; |
---|
93 | |
---|
94 | /** The labels for each property */ |
---|
95 | private String m_Names[]; |
---|
96 | |
---|
97 | /** The tool tip text for each property */ |
---|
98 | private String m_TipTexts[]; |
---|
99 | |
---|
100 | /** StringBuffer containing help text for the object being edited */ |
---|
101 | private StringBuffer m_HelpText; |
---|
102 | |
---|
103 | /** the GenericObjectEditor that was supplied for this node */ |
---|
104 | private GenericObjectEditor m_GenericObjectEditor; |
---|
105 | |
---|
106 | /** this Vector stores all of the possible combinations of parameters |
---|
107 | * that it obtains from its child nodes. These combinations are |
---|
108 | * created by the recursive combineAllValues method*/ |
---|
109 | private Vector m_WorkingSetCombinations; |
---|
110 | |
---|
111 | /** the tip text for our node editor to display */ |
---|
112 | private String m_ToolTipText; |
---|
113 | |
---|
114 | /** a reference to the tree model is necessary to be able to add and |
---|
115 | * remove nodes in the tree */ |
---|
116 | private DefaultTreeModel m_TreeModel; |
---|
117 | |
---|
118 | /** this is a reference to the Tree object that this node is |
---|
119 | * contained within. Its required for this node to be able to |
---|
120 | * add/remove nodes from the JTree*/ |
---|
121 | private JTree m_Tree; |
---|
122 | |
---|
123 | /** This is a reference to the parent panel of the JTree so that we can |
---|
124 | * supply it as the required argument when supplying warning JDialog |
---|
125 | * messages*/ |
---|
126 | private final AddModelsPanel m_ParentPanel; |
---|
127 | |
---|
128 | /** |
---|
129 | * The constructor initialiazes the member variables of this node, |
---|
130 | * Note that the "value" of this generic object is stored as the treeNode |
---|
131 | * user object. |
---|
132 | * |
---|
133 | * @param panel the reference to the parent panel for calls to JDialog |
---|
134 | * @param value the value stored at this tree node |
---|
135 | * @param genericObjectEditor the GenericObjectEditor for this object |
---|
136 | * @param toolTipText the tipText to be displayed for this object |
---|
137 | */ |
---|
138 | public GenericObjectNode(AddModelsPanel panel, Object value, |
---|
139 | GenericObjectEditor genericObjectEditor, String toolTipText) { |
---|
140 | |
---|
141 | super(value); |
---|
142 | //setObject(value); |
---|
143 | m_ParentPanel = panel; |
---|
144 | this.m_GenericObjectEditor = genericObjectEditor; |
---|
145 | this.m_ToolTipText = toolTipText; |
---|
146 | |
---|
147 | } |
---|
148 | |
---|
149 | /** |
---|
150 | * It seems kind of dumb that the reference to the tree model is passed in |
---|
151 | * seperately - but know that this is actually necessary. There is a really |
---|
152 | * weird chicken before the egg problem. You cannot create a TreeModel without |
---|
153 | * giving it its root node. However, the nodes in your tree can't update the |
---|
154 | * structure of the tree unless they have a reference to the TreeModel. So in |
---|
155 | * the end this was the only compromise that I could get to work well |
---|
156 | * |
---|
157 | * @param tree the tree to use |
---|
158 | */ |
---|
159 | public void setTree(JTree tree) { |
---|
160 | this.m_Tree = tree; |
---|
161 | this.m_TreeModel = (DefaultTreeModel) m_Tree.getModel(); |
---|
162 | |
---|
163 | } |
---|
164 | |
---|
165 | /** |
---|
166 | * returns the current tree |
---|
167 | * |
---|
168 | * @return the current tree |
---|
169 | */ |
---|
170 | public JTree getTree() { |
---|
171 | return m_Tree; |
---|
172 | } |
---|
173 | |
---|
174 | /** |
---|
175 | * A getter for the GenericObjectEditor for this node |
---|
176 | * |
---|
177 | * @return the editor |
---|
178 | */ |
---|
179 | public GenericObjectEditor getEditor() { |
---|
180 | return m_GenericObjectEditor; |
---|
181 | } |
---|
182 | |
---|
183 | /** |
---|
184 | * getter for the tooltip text |
---|
185 | * |
---|
186 | * @return tooltip text |
---|
187 | */ |
---|
188 | public StringBuffer getHelpText() { |
---|
189 | return m_HelpText; |
---|
190 | } |
---|
191 | |
---|
192 | /** |
---|
193 | * getter for the tooltip text |
---|
194 | * |
---|
195 | * @return tooltip text |
---|
196 | */ |
---|
197 | public String getToolTipText() { |
---|
198 | return m_ToolTipText; |
---|
199 | } |
---|
200 | |
---|
201 | /** |
---|
202 | * getter for this node's object |
---|
203 | * |
---|
204 | * @return the node's object |
---|
205 | */ |
---|
206 | public Object getObject() { |
---|
207 | return getUserObject(); |
---|
208 | } |
---|
209 | |
---|
210 | /** |
---|
211 | * setter for this nodes object |
---|
212 | * |
---|
213 | * @param newValue sets the new object |
---|
214 | */ |
---|
215 | public void setObject(Object newValue) { |
---|
216 | setUserObject(newValue); |
---|
217 | } |
---|
218 | |
---|
219 | /** |
---|
220 | * this is a simple filter for the setUserObject method. We basically |
---|
221 | * don't want null values to be passed in. |
---|
222 | * |
---|
223 | * @param o the object to set |
---|
224 | */ |
---|
225 | public void setUserObject(Object o) { |
---|
226 | if (o != null) |
---|
227 | super.setUserObject(o); |
---|
228 | } |
---|
229 | |
---|
230 | /** |
---|
231 | * getter for the parent panel |
---|
232 | * |
---|
233 | * @return the parent panel |
---|
234 | */ |
---|
235 | public JPanel getParentPanel() { |
---|
236 | return m_ParentPanel; |
---|
237 | } |
---|
238 | |
---|
239 | /** |
---|
240 | * returns always null |
---|
241 | * |
---|
242 | * @return always null |
---|
243 | */ |
---|
244 | public String toString() { |
---|
245 | return null; |
---|
246 | //return getClass().getName() + "[" + getUserObject().toString() + "]"; |
---|
247 | } |
---|
248 | |
---|
249 | /** |
---|
250 | * This implements the PropertyChangeListener for this node that gets |
---|
251 | * registered with its Editor. All we really have to do is change the |
---|
252 | * Object value stored internally at this node when its editor says the |
---|
253 | * value changed. |
---|
254 | * |
---|
255 | * @param evt the event |
---|
256 | */ |
---|
257 | public void propertyChange(PropertyChangeEvent evt) { |
---|
258 | |
---|
259 | Object newValue = ((GenericObjectEditor) evt.getSource()).getValue(); |
---|
260 | |
---|
261 | if (!newValue.getClass().equals(getObject().getClass())) { |
---|
262 | |
---|
263 | if (m_TreeModel.getRoot() == this) { |
---|
264 | |
---|
265 | try { |
---|
266 | m_ParentPanel.buildClassifierTree((Classifier) newValue |
---|
267 | .getClass().newInstance()); |
---|
268 | } catch (InstantiationException e) { |
---|
269 | e.printStackTrace(); |
---|
270 | } catch (IllegalAccessException e) { |
---|
271 | e.printStackTrace(); |
---|
272 | } |
---|
273 | m_ParentPanel.update(m_ParentPanel.getGraphics()); |
---|
274 | m_ParentPanel.repaint(); |
---|
275 | |
---|
276 | //System.out.println("Changed root"); |
---|
277 | |
---|
278 | } else { |
---|
279 | setObject(newValue); |
---|
280 | updateTree(); |
---|
281 | updateTree(); |
---|
282 | m_TreeModel.nodeChanged(this); |
---|
283 | } |
---|
284 | } |
---|
285 | } |
---|
286 | |
---|
287 | /** |
---|
288 | * This method uses introspection to programatically discover all of |
---|
289 | * the parameters for this generic object. For each one of them it |
---|
290 | * uses the TreeModel reference to create a new subtree to represent |
---|
291 | * that parameter and its value ranges. Note that all of these nodes |
---|
292 | * are PropertyNodes which themselves hold the logic of figuring out |
---|
293 | * what type of parameter it is they are representing and thus what |
---|
294 | * type of subtree to build. |
---|
295 | * <p/> |
---|
296 | * We need to be careful because this was molded from the code inside of |
---|
297 | * the PropertySheetPanel class. Which means that we are wide open |
---|
298 | * to copy/paste problems. In the future, when that code changes to |
---|
299 | * adapt to other changes in Weka then this could easily become broken. |
---|
300 | */ |
---|
301 | public void updateTree() { |
---|
302 | |
---|
303 | int childCount = m_TreeModel.getChildCount(this); |
---|
304 | |
---|
305 | for (int i = 0; i < childCount; i++) { |
---|
306 | DefaultMutableTreeNode child = (DefaultMutableTreeNode) m_TreeModel.getChild(this, 0); |
---|
307 | |
---|
308 | m_TreeModel.removeNodeFromParent(child); |
---|
309 | } |
---|
310 | |
---|
311 | //removeAllChildren(); |
---|
312 | |
---|
313 | Object classifier = this.getUserObject(); |
---|
314 | |
---|
315 | try { |
---|
316 | BeanInfo bi = Introspector.getBeanInfo(classifier.getClass()); |
---|
317 | m_Properties = bi.getPropertyDescriptors(); |
---|
318 | m_Methods = bi.getMethodDescriptors(); |
---|
319 | } catch (IntrospectionException ex) { |
---|
320 | System.err.println("PropertySheet: Couldn't introspect"); |
---|
321 | return; |
---|
322 | } |
---|
323 | |
---|
324 | // Look for a globalInfo method that returns a string |
---|
325 | // describing the target |
---|
326 | for (int i = 0; i < m_Methods.length; i++) { |
---|
327 | String name = m_Methods[i].getDisplayName(); |
---|
328 | Method meth = m_Methods[i].getMethod(); |
---|
329 | if (name.equals("globalInfo")) { |
---|
330 | if (meth.getReturnType().equals(String.class)) { |
---|
331 | try { |
---|
332 | Object args[] = {}; |
---|
333 | String globalInfo = (String) (meth.invoke(getObject(), |
---|
334 | args)); |
---|
335 | String summary = globalInfo; |
---|
336 | int ci = globalInfo.indexOf('.'); |
---|
337 | if (ci != -1) { |
---|
338 | summary = globalInfo.substring(0, ci + 1); |
---|
339 | } |
---|
340 | final String className = getObject().getClass().getName(); |
---|
341 | m_HelpText = new StringBuffer("NAME\n"); |
---|
342 | m_HelpText.append(className).append("\n\n"); |
---|
343 | m_HelpText.append("SYNOPSIS\n").append(globalInfo).append("\n\n"); |
---|
344 | |
---|
345 | } catch (Exception ex) { |
---|
346 | // ignored |
---|
347 | } |
---|
348 | } |
---|
349 | } |
---|
350 | } |
---|
351 | |
---|
352 | m_UsedPropertyIndexes = new Vector(); |
---|
353 | |
---|
354 | m_Editors = new PropertyEditor[m_Properties.length]; |
---|
355 | |
---|
356 | m_Values = new Object[m_Properties.length]; |
---|
357 | m_Names = new String[m_Properties.length]; |
---|
358 | m_TipTexts = new String[m_Properties.length]; |
---|
359 | boolean firstTip = true; |
---|
360 | |
---|
361 | for (int i = 0; i < m_Properties.length; i++) { |
---|
362 | |
---|
363 | // Don't display hidden or expert properties. |
---|
364 | if (m_Properties[i].isHidden() || m_Properties[i].isExpert()) { |
---|
365 | continue; |
---|
366 | } |
---|
367 | |
---|
368 | m_Names[i] = m_Properties[i].getDisplayName(); |
---|
369 | Class type = m_Properties[i].getPropertyType(); |
---|
370 | Method getter = m_Properties[i].getReadMethod(); |
---|
371 | Method setter = m_Properties[i].getWriteMethod(); |
---|
372 | |
---|
373 | // Only display read/write properties. |
---|
374 | if (getter == null || setter == null) { |
---|
375 | continue; |
---|
376 | } |
---|
377 | |
---|
378 | try { |
---|
379 | Object args[] = {}; |
---|
380 | Object value = getter.invoke(classifier, args); |
---|
381 | m_Values[i] = value; |
---|
382 | |
---|
383 | PropertyEditor editor = null; |
---|
384 | Class pec = m_Properties[i].getPropertyEditorClass(); |
---|
385 | if (pec != null) { |
---|
386 | try { |
---|
387 | editor = (PropertyEditor) pec.newInstance(); |
---|
388 | } catch (Exception ex) { |
---|
389 | // Drop through. |
---|
390 | } |
---|
391 | } |
---|
392 | if (editor == null) { |
---|
393 | editor = PropertyEditorManager.findEditor(type); |
---|
394 | } |
---|
395 | m_Editors[i] = editor; |
---|
396 | |
---|
397 | // If we can't edit this component, skip it. |
---|
398 | if (editor == null) { |
---|
399 | continue; |
---|
400 | } |
---|
401 | if (editor instanceof GenericObjectEditor) { |
---|
402 | ((GenericObjectEditor) editor).setClassType(type); |
---|
403 | } |
---|
404 | |
---|
405 | // Don't try to set null values: |
---|
406 | if (value == null) { |
---|
407 | continue; |
---|
408 | } |
---|
409 | |
---|
410 | editor.setValue(value); |
---|
411 | |
---|
412 | // now look for a TipText method for this property |
---|
413 | String tipName = m_Names[i] + "TipText"; |
---|
414 | for (int j = 0; j < m_Methods.length; j++) { |
---|
415 | String mname = m_Methods[j].getDisplayName(); |
---|
416 | Method meth = m_Methods[j].getMethod(); |
---|
417 | if (mname.equals(tipName)) { |
---|
418 | if (meth.getReturnType().equals(String.class)) { |
---|
419 | try { |
---|
420 | String tempTip = (String) (meth.invoke( |
---|
421 | classifier, args)); |
---|
422 | int ci = tempTip.indexOf('.'); |
---|
423 | if (ci < 0) { |
---|
424 | m_TipTexts[i] = tempTip; |
---|
425 | } else { |
---|
426 | m_TipTexts[i] = tempTip.substring(0, ci); |
---|
427 | } |
---|
428 | |
---|
429 | if (m_HelpText != null) { |
---|
430 | if (firstTip) { |
---|
431 | m_HelpText.append("OPTIONS\n"); |
---|
432 | firstTip = false; |
---|
433 | } |
---|
434 | m_HelpText.append(m_Names[i]).append(" -- "); |
---|
435 | m_HelpText.append(tempTip).append("\n\n"); |
---|
436 | |
---|
437 | } |
---|
438 | |
---|
439 | } catch (Exception ex) { |
---|
440 | |
---|
441 | } |
---|
442 | break; |
---|
443 | } |
---|
444 | } |
---|
445 | } |
---|
446 | |
---|
447 | //Here we update the usedPropertyIndexes variable so that |
---|
448 | //later on we will know which ones to look at. |
---|
449 | m_UsedPropertyIndexes.add(new Integer(i)); |
---|
450 | |
---|
451 | int currentCount = m_TreeModel.getChildCount(this); |
---|
452 | |
---|
453 | //Now we make a child node and add it to the tree underneath |
---|
454 | //this one |
---|
455 | PropertyNode newNode = new PropertyNode(m_Tree, m_ParentPanel, |
---|
456 | m_Names[i], m_TipTexts[i], m_Values[i], m_Editors[i]); |
---|
457 | |
---|
458 | m_TreeModel.insertNodeInto(newNode, this, currentCount); |
---|
459 | |
---|
460 | } catch (InvocationTargetException ex) { |
---|
461 | System.err.println("Skipping property " + m_Names[i] |
---|
462 | + " ; exception on target: " + ex.getTargetException()); |
---|
463 | ex.getTargetException().printStackTrace(); |
---|
464 | continue; |
---|
465 | } catch (Exception ex) { |
---|
466 | System.err.println("Skipping property " + m_Names[i] |
---|
467 | + " ; exception: " + ex); |
---|
468 | ex.printStackTrace(); |
---|
469 | continue; |
---|
470 | } |
---|
471 | |
---|
472 | } |
---|
473 | |
---|
474 | //Finally we tell the TreeModel to update itself so the changes |
---|
475 | //will be visible |
---|
476 | m_TreeModel.nodeStructureChanged(this); |
---|
477 | } |
---|
478 | |
---|
479 | /** |
---|
480 | * This method iterates over all of the child nodes of this |
---|
481 | * GenericObjectNode and requests the verious sets of values that the |
---|
482 | * user has presumably specified. Once these sets of values are |
---|
483 | * |
---|
484 | * @return a Vector consisting of all parameter combinations |
---|
485 | */ |
---|
486 | public Vector getValues() { |
---|
487 | |
---|
488 | Vector valuesVector = new Vector(); |
---|
489 | |
---|
490 | int childCount = m_TreeModel.getChildCount(this); |
---|
491 | |
---|
492 | //poll all child nodes for their values. |
---|
493 | for (int i = 0; i < childCount; i++) { |
---|
494 | |
---|
495 | PropertyNode currentChild = (PropertyNode) m_TreeModel.getChild( |
---|
496 | this, i); |
---|
497 | |
---|
498 | Vector v = currentChild.getAllValues(); |
---|
499 | valuesVector.add(v); |
---|
500 | |
---|
501 | } |
---|
502 | |
---|
503 | //Need to initialize the working set of paramter combinations |
---|
504 | m_WorkingSetCombinations = new Vector(); |
---|
505 | |
---|
506 | //obtain all combinations of the paremeters |
---|
507 | combineAllValues(new Vector(), valuesVector); |
---|
508 | |
---|
509 | /* |
---|
510 | //nice for initially debugging this - and there was a WHOLE lot of |
---|
511 | //that going on till this crazy idea finally worked. |
---|
512 | for (int i = 0; i < m_WorkingSetCombinations.size(); i++) { |
---|
513 | |
---|
514 | System.out.print("Combo "+i+": "); |
---|
515 | |
---|
516 | Vector current = (Vector)m_WorkingSetCombinations.get(i); |
---|
517 | for (int j = 0; j < current.size(); j++) { |
---|
518 | |
---|
519 | System.out.print(current.get(j)+"\t"); |
---|
520 | |
---|
521 | } |
---|
522 | |
---|
523 | System.out.print("\n"); |
---|
524 | } |
---|
525 | */ |
---|
526 | |
---|
527 | //Now the real work begins. Here we need to translate all of the values |
---|
528 | //received from the editors back into the actual class types that the |
---|
529 | //Weka classifiers will understand. for example, String values for |
---|
530 | //enumerated values need to be turned back into the SelectedTag objects |
---|
531 | //that classifiers understand. |
---|
532 | //This vector will hold all of the actual generic objects that are being |
---|
533 | //instantiated |
---|
534 | Vector newGenericObjects = new Vector(); |
---|
535 | |
---|
536 | for (int i = 0; i < m_WorkingSetCombinations.size(); i++) { |
---|
537 | |
---|
538 | Vector current = (Vector) m_WorkingSetCombinations.get(i); |
---|
539 | |
---|
540 | //create a new copy of this class. We will use this copy to test whether |
---|
541 | //the current set of parameters is valid. |
---|
542 | Object o = this.getUserObject(); |
---|
543 | Class c = o.getClass(); |
---|
544 | Object copy = null; |
---|
545 | |
---|
546 | try { |
---|
547 | copy = c.newInstance(); |
---|
548 | } catch (InstantiationException e) { |
---|
549 | e.printStackTrace(); |
---|
550 | } catch (IllegalAccessException e) { |
---|
551 | e.printStackTrace(); |
---|
552 | } |
---|
553 | |
---|
554 | for (int j = 0; j < current.size(); j++) { |
---|
555 | |
---|
556 | Object[] args = new Object[1]; |
---|
557 | |
---|
558 | int index = ((Integer) m_UsedPropertyIndexes.get(j)).intValue(); |
---|
559 | |
---|
560 | PropertyDescriptor property = (PropertyDescriptor) m_Properties[index]; |
---|
561 | Method setter = property.getWriteMethod(); |
---|
562 | Class[] params = setter.getParameterTypes(); |
---|
563 | |
---|
564 | Object currentVal = current.get(j); |
---|
565 | |
---|
566 | //System.out.println(currentVal.getClass().toString()); |
---|
567 | |
---|
568 | //we gotta turn strings back into booleans |
---|
569 | if (params.length == 1 |
---|
570 | && params[0].toString().equals("boolean") |
---|
571 | && currentVal.getClass().toString().equals( |
---|
572 | "class java.lang.String")) { |
---|
573 | |
---|
574 | currentVal = new Boolean((String) current.get(j)); |
---|
575 | } |
---|
576 | |
---|
577 | //we gotta turn strings back into "Tags" |
---|
578 | if (params.length == 1 |
---|
579 | && params[0].toString().equals( |
---|
580 | "class weka.core.SelectedTag") |
---|
581 | && currentVal.getClass().toString().equals( |
---|
582 | "class java.lang.String")) { |
---|
583 | |
---|
584 | String tagString = (String) current.get(j); |
---|
585 | |
---|
586 | m_Editors[index].setAsText(tagString); |
---|
587 | currentVal = m_Editors[index].getValue(); |
---|
588 | |
---|
589 | } |
---|
590 | |
---|
591 | args[0] = currentVal; |
---|
592 | |
---|
593 | /* |
---|
594 | System.out.print("setterName: "+setter.getName()+ |
---|
595 | " editor class: "+m_Editors[index].getClass()+ |
---|
596 | " params: "); |
---|
597 | |
---|
598 | |
---|
599 | for (int k = 0; k < params.length; k++) |
---|
600 | System.out.print(params[k].toString()+" "); |
---|
601 | |
---|
602 | System.out.println(" value class: "+args[0].getClass().toString()); |
---|
603 | */ |
---|
604 | |
---|
605 | try { |
---|
606 | |
---|
607 | //we tell the setter for the current parameter to update the copy |
---|
608 | //with the current parameter value |
---|
609 | setter.invoke(copy, args); |
---|
610 | |
---|
611 | } catch (InvocationTargetException ex) { |
---|
612 | if (ex.getTargetException() instanceof PropertyVetoException) { |
---|
613 | String message = "WARNING: Vetoed; reason is: " |
---|
614 | + ex.getTargetException().getMessage(); |
---|
615 | System.err.println(message); |
---|
616 | |
---|
617 | Component jf; |
---|
618 | jf = m_ParentPanel.getRootPane(); |
---|
619 | JOptionPane.showMessageDialog(jf, message, "error", |
---|
620 | JOptionPane.WARNING_MESSAGE); |
---|
621 | if (jf instanceof JFrame) |
---|
622 | ((JFrame) jf).dispose(); |
---|
623 | |
---|
624 | } else { |
---|
625 | System.err.println(ex.getTargetException().getClass() |
---|
626 | .getName() |
---|
627 | + " while updating " |
---|
628 | + property.getName() |
---|
629 | + ": " + ex.getTargetException().getMessage()); |
---|
630 | Component jf; |
---|
631 | jf = m_ParentPanel.getRootPane(); |
---|
632 | JOptionPane.showMessageDialog(jf, ex |
---|
633 | .getTargetException().getClass().getName() |
---|
634 | + " while updating " |
---|
635 | + property.getName() |
---|
636 | + ":\n" + ex.getTargetException().getMessage(), |
---|
637 | "error", JOptionPane.WARNING_MESSAGE); |
---|
638 | if (jf instanceof JFrame) |
---|
639 | ((JFrame) jf).dispose(); |
---|
640 | |
---|
641 | } |
---|
642 | |
---|
643 | } catch (IllegalArgumentException e) { |
---|
644 | e.printStackTrace(); |
---|
645 | } catch (IllegalAccessException e) { |
---|
646 | e.printStackTrace(); |
---|
647 | } |
---|
648 | |
---|
649 | } |
---|
650 | |
---|
651 | //At this point we have set all the parameters for this GenericObject |
---|
652 | //with a single combination that was generated from the |
---|
653 | //m_WorkingSetCombinations Vector and can add it to the collection that |
---|
654 | //will be returned |
---|
655 | newGenericObjects.add(copy); |
---|
656 | |
---|
657 | } |
---|
658 | |
---|
659 | return newGenericObjects; |
---|
660 | } |
---|
661 | |
---|
662 | /** This method is responsible for returning all possible values through |
---|
663 | * a recursive loop. |
---|
664 | * |
---|
665 | * When the recursion terminates that means that there are no more parameter |
---|
666 | * sets to branch out through so all we have to do is save the current Vector |
---|
667 | * in the working set of combinations. Otherwise we iterate through all |
---|
668 | * possible values left in the next set of parameter values and recursively |
---|
669 | * call this function. |
---|
670 | * |
---|
671 | * @param previouslySelected stores the values chosen in this branch of the recursion |
---|
672 | * @param remainingValues the sets of values left |
---|
673 | */ |
---|
674 | public void combineAllValues(Vector previouslySelected, |
---|
675 | Vector remainingValues) { |
---|
676 | |
---|
677 | if (remainingValues.isEmpty()) { |
---|
678 | m_WorkingSetCombinations.add(previouslySelected); |
---|
679 | return; |
---|
680 | } |
---|
681 | |
---|
682 | Vector currentSet = new Vector((Vector) remainingValues.get(0)); |
---|
683 | Vector tmpRemaining = new Vector(remainingValues); |
---|
684 | tmpRemaining.removeElementAt(0); |
---|
685 | |
---|
686 | for (int i = 0; i < currentSet.size(); i++) { |
---|
687 | Vector tmpPreviouslySelected = new Vector(previouslySelected); |
---|
688 | tmpPreviouslySelected.add(currentSet.get(i)); |
---|
689 | combineAllValues(tmpPreviouslySelected, tmpRemaining); |
---|
690 | } |
---|
691 | |
---|
692 | } |
---|
693 | |
---|
694 | } |
---|