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

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

Initial import : Genius 9.0.0

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