1 package nl.tudelft.simulation.dsol.swing.introspection.gui;
2
3 import java.lang.reflect.Array;
4 import java.lang.reflect.Constructor;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collection;
8 import java.util.Collections;
9 import java.util.Iterator;
10 import java.util.LinkedHashMap;
11 import java.util.List;
12 import java.util.Map;
13
14 import javax.swing.table.AbstractTableModel;
15
16 import org.djutils.immutablecollections.ImmutableCollection;
17 import org.djutils.logger.CategoryLogger;
18
19 import nl.tudelft.simulation.dsol.swing.introspection.table.DynamicTableModel;
20 import nl.tudelft.simulation.introspection.AbstractProperty;
21 import nl.tudelft.simulation.introspection.Introspector;
22 import nl.tudelft.simulation.introspection.Property;
23 import nl.tudelft.simulation.introspection.beans.BeanIntrospector;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public class CollectionTableModel extends AbstractTableModel implements IntrospectingTableModelInterface, DynamicTableModel
40 {
41
42 private static final long serialVersionUID = 20140831L;
43
44
45 protected Map<Integer, Object> instances = Collections.synchronizedMap(new LinkedHashMap<Integer, Object>(20));
46
47
48 protected List<Integer> keys = Collections.synchronizedList(new ArrayList<Integer>(20));
49
50
51 private Class<?> componentType = null;
52
53
54 private static final String[] COLUMNS = {"#", "+", "Instance"};
55
56
57 private List<ExpandButton> buttons = Collections.synchronizedList(new ArrayList<ExpandButton>(20));
58
59
60 private Property parentProperty;
61
62
63 private Introspector introspector;
64
65
66 private ModelManager manager = new DefaultModelManager();
67
68
69 private int maxKey = 0;
70
71
72
73
74
75 public CollectionTableModel(final Property parentProperty)
76 {
77 this(parentProperty, new BeanIntrospector());
78 }
79
80
81
82
83
84
85 public CollectionTableModel(final Property parentProperty, final Introspector introspector)
86 {
87 Object values;
88 try
89 {
90 values = parentProperty.getValue();
91 }
92 catch (Exception e)
93 {
94 values = new String("-");
95 }
96 if (values.getClass().isArray())
97 {
98 for (int i = 0; i < Array.getLength(values); i++)
99 {
100 addValue(Array.get(values, i));
101 }
102 }
103 if (values instanceof Collection)
104 {
105 for (Iterator<?> i = ((Collection<?>) values).iterator(); i.hasNext();)
106 {
107 addValue(i.next());
108 }
109 }
110 if (values instanceof ImmutableCollection)
111 {
112 for (Iterator<?> i = ((ImmutableCollection<?>) values).iterator(); i.hasNext();)
113 {
114 addValue(i.next());
115 }
116 }
117 this.parentProperty = parentProperty;
118 this.introspector = introspector;
119
120 for (int i = 0; i < this.instances.size(); i++)
121 {
122 this.buttons.add(new ExpandButton(getProperty(i), this));
123 }
124 }
125
126
127
128
129
130 private void addValue(final Object value)
131 {
132 Integer nextKey = Integer.valueOf(this.maxKey++);
133 this.keys.add(nextKey);
134 this.instances.put(nextKey, value);
135 }
136
137
138 @Override
139 public int getRowCount()
140 {
141 return this.instances.size();
142 }
143
144
145 @Override
146 public int getColumnCount()
147 {
148 return CollectionTableModel.COLUMNS.length;
149 }
150
151
152 @Override
153 public Object getValueAt(final int rowIndex, final int columnIndex)
154 {
155 if (columnIndex == 0)
156 {
157 return Integer.valueOf(rowIndex);
158 }
159 if (columnIndex == 1)
160 {
161 return this.buttons.get(rowIndex);
162 }
163 if (columnIndex == 2)
164 {
165 return this.instances.get(this.keys.get(rowIndex));
166 }
167 return null;
168 }
169
170
171 @Override
172 public String getColumnName(final int columnIndex)
173 {
174 return CollectionTableModel.COLUMNS[columnIndex];
175 }
176
177
178 @Override
179 public boolean isCellEditable(final int rowIndex, final int columnIndex)
180 {
181 if (columnIndex == 1 || columnIndex == 2)
182 {
183 return true;
184 }
185 return false;
186 }
187
188
189 @Override
190 public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex)
191 {
192 if (columnIndex == 2)
193 {
194 Integer key = this.keys.get(rowIndex);
195 this.instances.put(key, aValue);
196 }
197 this.update();
198 }
199
200
201
202
203 private void update()
204 {
205
206 List<Object> newValue = new ArrayList<Object>(this.keys.size());
207 for (int i = 0; i < this.keys.size(); i++)
208 {
209 newValue.add(this.instances.get(this.keys.get(i)));
210 }
211 this.parentProperty.setValue(newValue);
212 this.fireTableDataChanged();
213 }
214
215
216 @Override
217 public Class<?> getColumnClass(final int columnIndex)
218 {
219 if (columnIndex == 1)
220 {
221 return ExpandButton.class;
222 }
223 return Object.class;
224 }
225
226
227
228
229
230
231 @Override
232 public Property getProperty(final String propertyName)
233 {
234 int index = Integer.parseInt(propertyName);
235 return getProperty(index);
236 }
237
238
239
240
241
242 protected Property getProperty(final int index)
243 {
244 return new CollectionProperty(this.keys.get(index), this.parentProperty.getName());
245 }
246
247
248 @Override
249 public void createRow()
250 {
251 if (this.componentType == null)
252 {
253 this.componentType = this.parentProperty.getComponentType();
254 if (this.componentType == null)
255 {
256 return;
257 }
258 }
259 try
260 {
261 Constructor<?> instanceConstructor = this.componentType.getConstructor(new Class[0]);
262 Object instance = instanceConstructor.newInstance(new Object[0]);
263 addValue(instance);
264 this.buttons.add(new ExpandButton(getProperty(this.instances.size() - 1), this));
265 update();
266 }
267 catch (Exception e)
268 {
269 CategoryLogger.always().warn(e, "createRow: Could not instantiate new instance: ");
270 }
271 }
272
273
274 @Override
275 public void createRows(final int amount)
276 {
277 for (int i = 0; i < amount; i++)
278 {
279 this.createRow();
280 }
281 }
282
283
284 @Override
285 public void deleteRow(final int index)
286 {
287 Integer deletionKey = this.keys.get(index);
288 this.instances.remove(deletionKey);
289 this.keys.remove(index);
290 this.buttons.remove(index);
291 update();
292 }
293
294
295 @Override
296 public synchronized void deleteRows(final int[] indices)
297 {
298 Arrays.sort(indices);
299 for (int i = indices.length - 1; i >= 0; i--)
300 {
301 deleteRow(indices[i]);
302 }
303 }
304
305
306 @Override
307 public Introspector getIntrospector()
308 {
309 return this.introspector;
310 }
311
312
313 @Override
314 public Class<?> getTypeAt(final int rowIndex, final int columnIndex)
315 {
316 if (columnIndex == 0)
317 {
318 return String.class;
319 }
320 if (columnIndex == 1)
321 {
322 return ExpandButton.class;
323 }
324 if (columnIndex == 2)
325 {
326 return this.instances.get(this.keys.get(rowIndex)).getClass();
327 }
328 return null;
329 }
330
331
332
333
334
335 public void setModelManager(final ModelManager manager)
336 {
337 this.manager = manager;
338 }
339
340
341
342
343
344
345 @Override
346 public ModelManager getModelManager()
347 {
348 return this.manager;
349 }
350
351
352 @Override
353 public boolean isRowEditable()
354 {
355 return this.parentProperty.isEditable();
356 }
357
358
359
360
361 class CollectionProperty extends AbstractProperty implements Property
362 {
363
364 private final Integer key;
365
366
367 private final String name;
368
369
370
371
372
373
374
375 CollectionProperty(final Integer key, final String name)
376 {
377 this.key = key;
378 this.name = name;
379 }
380
381
382 @Override
383 public Object getInstance()
384 {
385 return CollectionTableModel.this.instances.values();
386 }
387
388
389 @Override
390 public String getName()
391 {
392 return this.name + "[" + CollectionTableModel.this.keys.indexOf(this.key) + "]";
393 }
394
395
396 @Override
397 public Class<?> getType()
398 {
399 return CollectionTableModel.this.instances.get(this.key).getClass();
400 }
401
402
403 @Override
404 public Object getValue()
405 {
406 try
407 {
408 return CollectionTableModel.this.instances.get(this.key);
409 }
410 catch (Exception e)
411 {
412 return new String("-");
413 }
414 }
415
416
417 @Override
418 public boolean isEditable()
419 {
420 return true;
421 }
422
423
424 @Override
425 protected void setRegularValue(final Object value)
426 {
427 throw new IllegalArgumentException(this + " is only supposed to be" + " set to composite values."
428 + "A program is not supposed to arrive here.");
429 }
430
431
432 @Override
433 public String toString()
434 {
435 return "Coll.Prop, key:" + this.key;
436 }
437 }
438
439
440 @Override
441 public String toString()
442 {
443 return "CollectionTableModel";
444 }
445
446 }