source: src/main/java/genius/gui/tree/NegotiatorTreeTableModel.java

Last change on this file was 127, checked in by Wouter Pasman, 6 years ago

#41 ROLL BACK of rev.126 . So this version is equal to rev. 125

File size: 12.9 KB
RevLine 
[127]1package genius.gui.tree;
2
3import java.util.Enumeration;
4import java.util.HashMap;
5import java.util.Map;
6
7import javax.swing.BorderFactory;
8import javax.swing.JTextField;
9import javax.swing.tree.TreePath;
10
11import genius.core.DomainImpl;
12import genius.core.issue.ISSUETYPE;
13import genius.core.issue.Issue;
14import genius.core.issue.IssueDiscrete;
15import genius.core.issue.IssueInteger;
16import genius.core.issue.IssueReal;
17import genius.core.issue.Objective;
18import genius.core.jtreetable.AbstractTreeTableModel;
19import genius.core.jtreetable.TreeTableModel;
20import genius.core.utility.AdditiveUtilitySpace;
21
22/**
23 * Tree model for editing {@link AdditiveUtilitySpace}.
24 */
25public class NegotiatorTreeTableModel extends AbstractTreeTableModel
26 implements TreeTableModel {
27
28 private static final String NAME = "Name";
29 private static final String TYPE = "Type";
30 private static final String NUMBER = "Number";
31 private static final String VALUE = "Value";
32 private static final String WEIGHT = "Weight";
33
34 private Objective root;
35 private DomainImpl domain;
36 private String[] colNames;
37 private Class[] colTypes;
38 private AdditiveUtilitySpace utilitySpace;
39 private boolean containsUtilitySpace;
40 private Map<Objective, JTextField> names;
41 private Map<Objective, JTextField> types;
42 private Map<Objective, JTextField> numbers;
43 private Map<Objective, WeightSlider> sliders;
44 private Map<Objective, IssueValuePanel> issueValues; // Contains objects
45 // representing the
46 // possible values
47 // of an issue
48
49 private static final String[] domainColNames = { NAME, TYPE, /* NUMBER, */
50 VALUE };
51 private static final Class[] domainColTypes = { TreeTableModel.class,
52 JTextField.class, /* JTextField.class, */IssueValuePanel.class };
53 private static final String[] domainAndUtilityColNames = { NAME,
54 TYPE, /*
55 * NUMBER ,
56 */
57 VALUE, WEIGHT };
58 private static final Class[] domainAndUtilityColTypes = {
59 TreeTableModel.class, JTextField.class, /* JTextField.class, */
60 IssueValuePanel.class, WeightSlider.class };
61
62 /**
63 * Create new profile for domain
64 *
65 * @param domain
66 * the domain to edit
67 */
68 public NegotiatorTreeTableModel(DomainImpl domain) {
69 this.domain = domain;
70 this.root = domain.getObjectivesRoot();
71 this.containsUtilitySpace = false;
72 this.colNames = domainColNames;
73 this.colTypes = domainColTypes;
74 names = new HashMap<Objective, JTextField>();
75 types = new HashMap<Objective, JTextField>();
76 numbers = new HashMap<Objective, JTextField>();
77 issueValues = new HashMap<Objective, IssueValuePanel>();
78 }
79
80 /**
81 * Edit existing profile in domain
82 *
83 * @param domain
84 * the domain of the profile
85 * @param utilitySpace
86 * the profile to edit
87 */
88 public NegotiatorTreeTableModel(DomainImpl domain,
89 AdditiveUtilitySpace utilitySpace) {
90 this.domain = domain;
91 this.root = domain.getObjectivesRoot();
92 this.utilitySpace = utilitySpace;
93 this.containsUtilitySpace = true;
94 this.colNames = domainAndUtilityColNames;
95 this.colTypes = domainAndUtilityColTypes;
96 names = new HashMap<Objective, JTextField>();
97 types = new HashMap<Objective, JTextField>();
98 numbers = new HashMap<Objective, JTextField>();
99 issueValues = new HashMap<Objective, IssueValuePanel>();
100 sliders = new HashMap<Objective, WeightSlider>();
101
102 }
103
104 /**
105 * @return the root Object of the tree.
106 */
107 @Override
108 public Object getRoot() {
109 return root;
110 }
111
112 /**
113 * @return true if and only if node is an Issue.
114 */
115 @Override
116 public boolean isLeaf(Object node) {
117 return (node instanceof Issue);
118 }
119
120 /**
121 *
122 * @param row
123 * the row number of the cell.
124 * @param col
125 * the column number of the cell.
126 * @return if the given cell is editable.
127 */
128 public boolean isCellEditable(int row, int col) {
129 if (col >= colTypes.length || col < 0)
130 return false;
131 else if (colTypes[col] == TreeTableModel.class)
132 return true;
133 else if (colTypes[col] == WeightSlider.class)
134 return true;
135 else
136 return false;
137 }
138
139 @Override
140 public boolean isCellEditable(Object node, int column) {
141 return isCellEditable(-1, column);
142 }
143
144 /**
145 * Method is empty at the moment. Default implementation from
146 * AbstractTreeTableModel.
147 */
148 @Override
149 public void valueForPathChanged(TreePath path, Object newValue) {
150 }
151
152 /**
153 * @return the number of columns for the TreeTable.
154 */
155 @Override
156 public int getColumnCount() {
157 return colNames.length;
158 }
159
160 /**
161 * @return the name of column. If column >= getColumnCount, an empty String
162 * is returned.
163 */
164 @Override
165 public String getColumnName(int column) {
166 if (column < getColumnCount())
167 return colNames[column];
168 else
169 return "";
170 }
171
172 @Override
173 public Class getColumnClass(int column) {
174 return colTypes[column];
175 }
176
177 /**
178 * When node is an Objective, this method returns the object beloging in the
179 * given column. If node is no Objective, or column has an invalid value,
180 * null is returned.
181 *
182 * @return the contents of column, for the given node.
183 */
184 @Override
185 public Object getValueAt(Object node, int column) {
186 Objective objective;
187 if (!(node instanceof Objective) || getColumnCount() <= column
188 || column < 0)
189 return null;
190 else
191 objective = (Objective) node;
192
193 // TODO Maybe also instanceof Issue.
194 // do the rest
195 // Also, when only editing Objectives, don't show anything after the
196 // objective columns. <-- already happens automatically due to
197 // getColumnCount()
198
199 /*
200 * switch(column) { case 0: return objective.getName(); case 1: return
201 * objective.getType(); case 2: return objective.getNumber(); case 3:
202 * return utilitySpace.getEvaluator(objective.getNumber());//Is this
203 * going to work in all cases? Answer: no case 4: return
204 * getWeightSlider(objective); }
205 */
206
207 // if (getColumnName(column).equals(arg0))
208 if (getColumnName(column) == NAME)
209 return getNameField(objective);
210 else if (getColumnName(column) == TYPE)
211 return getTypeField(objective);
212 else if (getColumnName(column) == NUMBER)
213 return getNumberField(objective);
214 else if (getColumnName(column) == VALUE)
215 return getIssueValuePanel(objective);
216 else if (getColumnName(column) == WEIGHT)
217 if (utilitySpace instanceof AdditiveUtilitySpace) {
218 return getWeightSlider(objective);
219 } else {
220 return null;
221 }
222
223 return null;
224 }
225
226 /**
227 * Returns parent's child at the given index. If parent is not of type
228 * Objective, or index is invalid, null is returned.
229 */
230 @Override
231 public Object getChild(Object parent, int index) {
232 if (!(parent instanceof Objective)
233 || ((Objective) parent).getChildCount() <= index || index < 0)
234 return null;
235 else
236 return ((Objective) parent).getChildAt(index);
237 }
238
239 /**
240 * If parent is instanceof Objective, returns the number of children.
241 * Otherwise, 0 is returned.
242 */
243 @Override
244 public int getChildCount(Object parent) {
245 if (parent instanceof Objective)
246 return ((Objective) parent).getChildCount();
247 else
248 return 0;
249 }
250
251 /**
252 * Recursively calculates the highest Objective / Issue number in the tree.
253 *
254 * @return the highest Objective / Issue number in the tree, or -1.
255 */
256 public int getHighestObjectiveNr() {
257 if (root != null)
258 return root.getHighestObjectiveNr(-1);
259 else
260 return -1;
261 }
262
263 /**
264 *
265 * @return the Domain.
266 */
267 public DomainImpl getDomain() {
268 return domain;
269 }
270
271 /**
272 *
273 * @return the UtilitySpace.
274 */
275 public AdditiveUtilitySpace getUtilitySpace() {
276 return utilitySpace;
277 }
278
279 /**
280 * Sets this model's UtilitySpace. A UtilitySpace is required to map
281 * utilities to treeNodes.
282 *
283 * @param space
284 * a UtilitySpace object.
285 */
286 public void setUtilitySpace(AdditiveUtilitySpace space) {
287 utilitySpace = space;
288
289 if (space != null) {
290 containsUtilitySpace = true;
291 colNames = domainAndUtilityColNames;
292 colTypes = domainAndUtilityColTypes;
293 } else {
294 containsUtilitySpace = false;
295 colNames = domainColNames;
296 colTypes = domainColTypes;
297 }
298 }
299
300 public void updateWeights(WeightSlider caller, double newWeight) {
301 // Calculate the new weights for the tree, and return to caller with the
302 // caller's new weight. This new weight can be
303 // different from the requested weight, for instance if that
304 // modification is impossible for some reason.
305
306 // Root may not be null!
307 Enumeration<Objective> objectives = root.getPreorderEnumeration();
308 while (objectives.hasMoreElements()) {
309 Objective obj = objectives.nextElement();
310 double updatedWeight = utilitySpace.getWeight(obj.getNumber());
311 getWeightSlider(obj).setWeight(updatedWeight);
312 }
313 }
314
315 protected JTextField getNameField(Objective node) {
316 JTextField field = names.get(node);
317 if (field == null) {
318 field = new JTextField(node.getName());
319 field.setBorder(BorderFactory.createEmptyBorder());
320 setNameField(node, field);
321 }
322 return field;
323 }
324
325 protected JTextField getTypeField(Objective node) {
326 JTextField field = types.get(node);
327 if (field == null) {
328 field = new JTextField("" + node.getType());
329 field.setBorder(BorderFactory.createEmptyBorder());
330 setTypeField(node, field);
331 }
332 return field;
333 }
334
335 protected JTextField getNumberField(Objective node) {
336 JTextField field = numbers.get(node);
337 if (field == null) {
338 field = new JTextField("" + node.getNumber());
339 field.setBorder(BorderFactory.createEmptyBorder());
340 setNumberField(node, field);
341 }
342 return field;
343 }
344
345 /**
346 * Returns the WeightSlider belonging to the given Objective. If there is no
347 * WeightSlider attached to the given Objective, a new one is created and
348 * added using setWeightSlider(Objective, WeightSlider).
349 *
350 * @param node
351 * an Objective.
352 * @return the slider associated with node.
353 */
354 public WeightSlider getWeightSlider(Objective node) {
355 WeightSlider slider = sliders.get(node);
356 if (slider == null) {
357 slider = new WeightSlider(this, node);
358 setWeightSlider(node, slider);
359
360 if (utilitySpace != null) {
361 slider.setWeight(utilitySpace.getWeight(node.getNumber()));
362 } else {
363 slider.setWeight(0.5);
364 }
365 }
366 return slider;
367 }
368
369 /**
370 * Sets the WeightSlider object for the given Objective.
371 *
372 * @param node
373 * Objective to attach the slider to.
374 * @param slider
375 * the WeightSlider to be attached to node.
376 */
377 protected void setWeightSlider(Objective node, WeightSlider slider) {
378 sliders.put(node, slider);
379 }
380
381 protected void setNameField(Objective node, JTextField field) {
382 names.put(node, field);
383 }
384
385 protected void setTypeField(Objective node, JTextField field) {
386 types.put(node, field);
387 }
388
389 protected void setNumberField(Objective node, JTextField field) {
390 numbers.put(node, field);
391 }
392
393 public IssueValuePanel getIssueValuePanel(Objective node) {
394 if (utilitySpace != null
395 && !(utilitySpace instanceof AdditiveUtilitySpace))
396 return null;
397 IssueValuePanel value = issueValues.get(node);
398 if (value == null) {
399 if (node.getType() == ISSUETYPE.DISCRETE) {
400 value = new IssueDiscreteValuePanel(this, (IssueDiscrete) node);
401 } else if (node.getType() == ISSUETYPE.INTEGER) {
402 value = new IssueIntegerValuePanel(this, (IssueInteger) node);
403 } else if (node.getType() == ISSUETYPE.REAL) {
404 value = new IssueRealValuePanel(this, (IssueReal) node);
405 } else if (node.getType() == ISSUETYPE.OBJECTIVE) {
406 value = new ObjectiveValuePanel(this, node);
407 }
408 setIssueValuePanel(node, value);
409 }
410 return value;
411 }
412
413 protected void setIssueValuePanel(Objective node, IssueValuePanel panel) {
414 issueValues.put(node, panel);
415 }
416
417 /**
418 * Notifies the listeners that the structure of the tree has changed. In
419 * it's current implementation, this method is just a wrapper for the
420 * protected method fireTreeStructureChanged where the child index array and
421 * the children array are left empty. Wouter: be careful with calling this,
422 * The GUI below the source point will be collapsed
423 *
424 * @param source
425 * the source that triggered the change.
426 * @param path
427 * a TreePath object that identifies the path to the parent of
428 * the modified item(s)
429 */
430 public void treeStructureChanged(Object source, Object[] path) {
431 fireTreeStructureChanged(source, path, new int[0], new Object[0]);
432 }
433
434 /**
435 * Wouter: added to handle change of values without change of tree
436 * structure.
437 *
438 * @param source
439 * the source that triggered the change.
440 * @param path
441 * path a TreePath object that identifies the path to the parent
442 * of the modified item(s)
443 */
444 public void treeNodesChanged(Object source, Object[] path) {
445 fireTreeNodesChanged(source, path, new int[0], new Object[0]);
446 }
447}
Note: See TracBrowser for help on using the repository browser.