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