View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans-Common.
5    *
6    * CosyBeans-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.gui.components.introspection;
21  
22  import java.awt.CardLayout;
23  import java.awt.event.WindowAdapter;
24  import java.awt.event.WindowEvent;
25  
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Comparator;
29  import java.util.Map;
30  
31  import javax.swing.JFrame;
32  import javax.swing.JPanel;
33  import javax.swing.JScrollPane;
34  import javax.swing.JTable;
35  import javax.swing.table.AbstractTableModel;
36  
37  
38  /**
39   * A TableModel implementation that handles key-value maps to be used with
40   * JTable
41   *
42   * @author <a href="mailto:miha.kadunc@cosylab.com">Miha Kadunc</a>
43   * @version $id$
44   */
45  public class MapTableModel extends AbstractTableModel
46  {
47  
48  	private static final long serialVersionUID = 1L;
49  
50  	String[] columns = { "key", "value", "info" };
51  
52  	/** flags for keys and values */
53  	boolean[] editable = { false, true, false };
54  	ArrayList keys = null;
55  	ArrayList values = null;
56  	ArrayList keyInfo = null;
57  	int[] colMap = { 0, 1, 2 };
58  
59  	/** Forces table to sort map by key names (key.toString()). */
60  	private boolean sortByKeyName = true;
61  
62  	private class KeyComparator implements Comparator
63  	{
64  		/* (non-Javadoc)
65  		    * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
66  		    */
67  		public int compare(Object o1, Object o2)
68  		{
69  			return String.valueOf(o1).compareTo(String.valueOf(o2));
70  		}
71  	}
72  
73  	/**
74  	 * DOCUMENT ME!
75  	 *
76  	 * @param args String[]
77  	 */
78  	public static void main(String[] args)
79  	{
80  		JFrame frame = new JFrame();
81  		JPanel panel = new JPanel();
82  		MapTableModel model = new MapTableModel(new String[]{ "property", "value" });
83  		JTable table = new JTable(model);
84  		JScrollPane pane = new JScrollPane(table);
85  
86  		model.setKeys(new String[]{ "1", "2", "3" });
87  		model.setValues(new String[]{ "val1", "val2", "val3" });
88  
89  		panel.setLayout(new CardLayout());
90  		panel.add(pane, "table");
91  		frame.setContentPane(panel);
92  		frame.setBounds(100, 100, 300, 200);
93  
94  		frame.addWindowListener(new WindowAdapter() {
95  				/**
96  				 * @see java.awt.event.WindowAdapter#windowClosed(WindowEvent)
97  				 */
98  				public void windowClosed(WindowEvent e)
99  				{
100 					System.exit(0);
101 				}
102 			});
103 		frame.setVisible(true);
104 	}
105 
106 	/**
107 	 * Creation date: (3.1.2002 17:04:55)
108 	 */
109 	public MapTableModel()
110 	{
111 		keys = new ArrayList();
112 		values = new ArrayList();
113 		fireTableStructureChanged();
114 	}
115 
116 	/**
117 	 * Creation date: (3.1.2002 17:04:55)
118 	 *
119 	 * @param columnNames DOCUMENT ME!
120 	 */
121 	public MapTableModel(String[] columnNames)
122 	{
123 		this();
124 
125 		if (columnNames.length > 2) {
126 			keyInfo = new ArrayList();
127 		}
128 
129 		columns = columnNames;
130 	}
131 
132 	/**
133 	 * Creation date: (3.1.2002 17:04:55)
134 	 *
135 	 * @param columnNames String[]
136 	 * @param keys Object[]
137 	 */
138 	public MapTableModel(String[] columnNames, Object[] keys)
139 	{
140 		this(columnNames);
141 		setKeys(keys);
142 	}
143 
144 	/**
145 	 * Creation date: (3.1.2002 17:04:55)
146 	 *
147 	 * @param columnNames String[]
148 	 * @param map Map
149 	 */
150 	public MapTableModel(String[] columnNames, Map map)
151 	{
152 		this(columnNames);
153 		setMap(map);
154 	}
155 
156 	/**
157 	 * Creation date: (3.1.2002 16:34:43)
158 	 *
159 	 * @param index int
160 	 * @param map Map
161 	 */
162 	public void addMap(int index, Map map)
163 	{
164 		internalAddMap(index, map);
165 		fireTableRowsInserted(index, index + map.size());
166 	}
167 
168 	/**
169 	 * Creation date: (3.1.2002 16:34:43)
170 	 *
171 	 * @param map Map
172 	 */
173 	public void addMap(Map map)
174 	{
175 		addMap(keys.size(), map);
176 	}
177 
178 	/**
179 	 * Creation date: (3.1.2002 16:34:43)
180 	 *
181 	 * @param index int
182 	 * @param key java.lang.Object
183 	 * @param value java.lang.Object
184 	 */
185 	public void addRow(int index, Object key, Object value)
186 	{
187 		internalAddRow(index, key, value, "");
188 		fireTableRowsInserted(index, index);
189 	}
190 
191 	/**
192 	 * DOCUMENT ME!
193 	 *
194 	 * @param index int
195 	 * @param key Object
196 	 * @param value Object
197 	 * @param keyInfo String
198 	 */
199 	public void addRow(int index, Object key, Object value, String keyInfo)
200 	{
201 		internalAddRow(index, key, value, keyInfo);
202 		fireTableRowsInserted(index, index);
203 	}
204 
205 	/**
206 	 * Creation date: (3.1.2002 16:34:43)
207 	 *
208 	 * @param key java.lang.Object
209 	 * @param value java.lang.Object
210 	 */
211 	public void addRow(Object key, Object value)
212 	{
213 		addRow(keys.size(), key, value);
214 	}
215 
216 	/**
217 	 * DOCUMENT ME!
218 	 *
219 	 * @param key Object
220 	 * @param value Object
221 	 * @param keyInfo String
222 	 */
223 	public void addRow(Object key, Object value, String keyInfo)
224 	{
225 		addRow(keys.size(), key, value, keyInfo);
226 	}
227 
228 	/**
229 	 * Removes all mappings from this map (optional operation).
230 	 */
231 	public void clear()
232 	{
233 		keys.clear();
234 		values.clear();
235 		keyInfo = null;
236 		fireTableStructureChanged();
237 	}
238 
239 	/**
240 	 * Creation date: (3.1.2002 16:34:43)
241 	 *
242 	 * @return Object[][]
243 	 */
244 	public Object[][] getAsArray()
245 	{
246 		Object[][] u = new Object[keys.size()][2];
247 
248 		for (int i = 0; i < keys.size(); i++) {
249 			u[i][0] = keys.get(i);
250 			u[i][1] = values.get(i);
251 		}
252 
253 		return u;
254 	}
255 
256 	/**
257 	 * DOCUMENT ME!
258 	 *
259 	 * @return int
260 	 *
261 	 * @see AbstractTableModel#getColumnCount()
262 	 */
263 	public int getColumnCount()
264 	{
265 		if (keyInfo != null) {
266 			return 3;
267 		}
268 
269 		return 2;
270 	}
271 
272 	/**
273 	 * DOCUMENT ME!
274 	 *
275 	 * @param index int
276 	 *
277 	 * @return String
278 	 *
279 	 * @see AbstractTableModel#getColumnName(int)
280 	 */
281 	public String getColumnName(int index)
282 	{
283 		return columns[colMap[index]].toString();
284 	}
285 
286 	/**
287 	 * Creation date: (3.1.2002 16:34:43)
288 	 *
289 	 * @return java.util.Hashtable
290 	 */
291 	public java.util.Hashtable getMap()
292 	{
293 		java.util.Hashtable map = new java.util.Hashtable(keys.size());
294 
295 		for (int i = 0; i < keys.size(); i++) {
296 			Object v = values.get(i);
297 			Object k = keys.get(i);
298 
299 			if (v == null) {
300 				v = "";
301 			}
302 
303 			if (k == null) {
304 				k = "";
305 			}
306 
307 			map.put(k, v);
308 		}
309 
310 		return map;
311 	}
312 
313 	/**
314 	 * DOCUMENT ME!
315 	 *
316 	 * @return int
317 	 *
318 	 * @see AbstractTableModel#getRowCount()
319 	 */
320 	public int getRowCount()
321 	{
322 		return keys.size();
323 	}
324 
325 	/**
326 	 * DOCUMENT ME!
327 	 *
328 	 * @param row int
329 	 * @param column int
330 	 *
331 	 * @return Object
332 	 *
333 	 * @see AbstractTableModel#getValueAt(int, int)
334 	 */
335 	public Object getValueAt(int row, int column)
336 	{
337 		if ((column == 0) && (keys != null)) {
338 			return keys.get(row);
339 		} else if ((column == colMap[1]) && (values != null)) {
340 			return values.get(row);
341 		} else if ((column == colMap[2]) && (keyInfo != null)) {
342 			return keyInfo.get(row);
343 		} else {
344 			return "";
345 		}
346 	}
347 
348 	/**
349 	 * Creation date: (3.1.2002 16:34:43)
350 	 *
351 	 * @param index int
352 	 * @param keys java.lang.Object
353 	 */
354 	private void internalAddKeys(int index, Object[] keys)
355 	{
356 		for (int i = 0; i < keys.length; i++) {
357 			internalAddRow(index + i, keys[i], null, "");
358 		}
359 	}
360 
361 	/**
362 	 * Creation date: (3.1.2002 16:34:43)
363 	 *
364 	 * @param index int
365 	 * @param map java.lang.Object
366 	 */
367 	private void internalAddMap(int index, Map map)
368 	{
369 		Object[] newKeys = map.keySet().toArray();
370 		Arrays.sort(newKeys, new KeyComparator());
371 
372 		for (int i = 0; i < newKeys.length; i++) {
373 			internalAddRow(index + i, newKeys[i], map.get(newKeys[i]), "");
374 		}
375 	}
376 
377 	private void internalAddRow(int index, Object key, Object value,
378 	    String keyInfo)
379 	{
380 		if (this.keyInfo != null) {
381 			this.keyInfo.add(keyInfo);
382 		}
383 
384 		keys.add(index, key);
385 		values.add(index, value);
386 	}
387 
388 	/**
389 	 * Removes all mappings from this map (optional operation).
390 	 */
391 	private void internalClear()
392 	{
393 		keys.clear();
394 		values.clear();
395 		keyInfo = null;
396 	}
397 
398 	/**
399 	 * Creation date: (3.1.2002 16:34:43)
400 	 *
401 	 * @param index int
402 	 */
403 	private void internalRemoveRow(int index)
404 	{
405 		keys.remove(index);
406 		values.remove(index);
407 
408 		if (keyInfo != null) {
409 			keyInfo.remove(index);
410 		}
411 	}
412 
413 	/**
414 	 * DOCUMENT ME!
415 	 *
416 	 * @param row int
417 	 * @param column int
418 	 *
419 	 * @return boolean
420 	 *
421 	 * @see AbstractTableModel#isCellEditable(int, int)
422 	 */
423 	public boolean isCellEditable(int row, int column)
424 	{
425 		return editable[colMap[column]];
426 	}
427 
428 	/**
429 	 * DOCUMENT ME!
430 	 *
431 	 * @return boolean
432 	 */
433 	public boolean isKeyEditable()
434 	{
435 		return editable[0];
436 	}
437 
438 	/**
439 	 * DOCUMENT ME!
440 	 *
441 	 * @return boolean
442 	 */
443 	public boolean isValueEditable()
444 	{
445 		return editable[1];
446 	}
447 
448 	/**
449 	 * Creation date: (3.1.2002 16:34:43)
450 	 *
451 	 * @param index int
452 	 */
453 	public void removeRow(int index)
454 	{
455 		internalRemoveRow(index);
456 		fireTableRowsDeleted(index, index);
457 	}
458 
459 	/**
460 	 * Creation date: (3.1.2002 16:34:43)
461 	 *
462 	 * @param key java.lang.Object
463 	 */
464 	public void removeRow(Object key)
465 	{
466 		int index = keys.indexOf(key);
467 		removeRow(index);
468 	}
469 
470 	/**
471 	 * Creation date: (3.1.2002 16:34:43)
472 	 *
473 	 * @param u Object[][]
474 	 */
475 	public synchronized void setAsArray(Object[][] u)
476 	{
477 		internalClear();
478 
479 		for (int i = 0; i < u.length; i++) {
480 			internalAddRow(i, u[i][1], u[i][2], "");
481 		}
482 
483 		fireTableDataChanged();
484 	}
485 
486 	/**
487 	 * DOCUMENT ME!
488 	 *
489 	 * @param name String
490 	 *
491 	 * @see AbstractTableModel#getColumnName(int)
492 	 */
493 	public void setKeyColumnName(String name)
494 	{
495 		synchronized (columns) {
496 			columns[0] = name;
497 		}
498 
499 		fireTableStructureChanged();
500 	}
501 
502 	/**
503 	 * DOCUMENT ME!
504 	 *
505 	 * @param name String
506 	 */
507 	public void setValueColumnName(String name)
508 	{
509 		synchronized (columns) {
510 			columns[1] = name;
511 		}
512 
513 		fireTableStructureChanged();
514 	}
515 
516 	/**
517 	 * DOCUMENT ME!
518 	 *
519 	 * @param name String
520 	 */
521 	public void setKeyInfoColumnName(String name)
522 	{
523 		columns[2] = name;
524 		fireTableStructureChanged();
525 	}
526 
527 	/**
528 	 * DOCUMENT ME!
529 	 *
530 	 * @param value boolean
531 	 */
532 	public void setKeyEditable(boolean value)
533 	{
534 		editable[0] = value;
535 	}
536 
537 	/**
538 	 * Creation date: (3.1.2002 16:34:43)
539 	 *
540 	 * @param keys Object[]
541 	 */
542 	public synchronized void setKeys(Object[] keys)
543 	{
544 		this.keys.clear();
545 		internalAddKeys(getRowCount(), keys);
546 		fireTableDataChanged();
547 	}
548 
549 	/**
550 	 * DOCUMENT ME!
551 	 *
552 	 * @param map Map
553 	 */
554 	public synchronized void setMap(Map map)
555 	{
556 		internalClear();
557 		internalAddMap(getRowCount(), map);
558 		fireTableDataChanged();
559 	}
560 
561 	/**
562 	 * DOCUMENT ME!
563 	 *
564 	 * @param value Object
565 	 * @param row int
566 	 * @param column int
567 	 *
568 	 * @see AbstractTableModel#setValueAt(int, int)
569 	 */
570 	public void setValueAt(Object value, int row, int column)
571 	{
572 		if (column == colMap[0]) {
573 			keys.set(row, value);
574 		} else if (column == colMap[1]) {
575 			values.set(row, value);
576 		}
577 
578 		fireTableCellUpdated(row, column);
579 	}
580 
581 	/**
582 	 * DOCUMENT ME!
583 	 *
584 	 * @param value boolean
585 	 */
586 	public void setValueEditable(boolean value)
587 	{
588 		editable[1] = value;
589 	}
590 
591 	/**
592 	 * DOCUMENT ME!
593 	 *
594 	 * @return String
595 	 */
596 	public String toString()
597 	{
598 		StringBuffer b = new StringBuffer();
599 		b.append(columns[0]);
600 		b.append(" - ");
601 		b.append(columns[1]);
602 
603 		for (int i = 0; i < keys.size(); i++) {
604 			b.append("\n");
605 			b.append(keys.get(i));
606 
607 			if (keyInfo != null) {
608 				b.append(" (");
609 				b.append(keyInfo.get(i));
610 				b.append(") ");
611 			}
612 
613 			b.append(" - ");
614 			b.append(values.get(i));
615 		}
616 
617 		return b.toString();
618 	}
619 
620 	/**
621 	 * DOCUMENT ME!
622 	 *
623 	 * @param keyInfo String[]
624 	 */
625 	public synchronized void setKeyInfo(String[] keyInfo)
626 	{
627 		this.keyInfo = new ArrayList(java.util.Arrays.asList(keyInfo));
628 
629 		int[] temp = { 0, 2, 1 };
630 		colMap = temp;
631 		fireTableStructureChanged();
632 	}
633 
634 	/**
635 	 * DOCUMENT ME!
636 	 *
637 	 * @param values Object[]
638 	 *
639 	 * @see AbstractTableModel#setValueAt(int, int)
640 	 */
641 	public void setValues(Object[] values)
642 	{
643 		this.values.clear();
644 		this.values.addAll(java.util.Arrays.asList(values));
645 		fireTableDataChanged();
646 	}
647 
648 	/**
649 	 * Returns <code>true</code> if contained keys are sorted by their names
650 	 * obtained by toString() method.
651 	 *
652 	 * @return <code>true</code> if contained keys are sorted by their names
653 	 *         obtained by toString().
654 	 */
655 	public boolean isSortByKeyName()
656 	{
657 		return sortByKeyName;
658 	}
659 
660 	/**
661 	 * Set <code>true</code> to force contained keys to be sorted by their
662 	 * names obtained by toString() method.
663 	 *
664 	 * @param b
665 	 */
666 	public void setSortByKeyName(boolean b)
667 	{
668 		sortByKeyName = b;
669 	}
670 
671 	/**
672 	 * Puts new value under under specified key. If key does not exist, new
673 	 * kay-value pair is aded to the end of the table.
674 	 *
675 	 * @param key the key for which value is to be updated
676 	 * @param value new value
677 	 *
678 	 * @return old value under key or <code>null</code> if no previous value
679 	 *         existed
680 	 */
681 	public Object put(Object key, Object value)
682 	{
683 		int i = keys.indexOf(key);
684 
685 		if (i > -1) {
686 			Object r = values.get(i);
687 			values.set(i, value);
688 
689 			fireTableCellUpdated(i, colMap[1]);
690 
691 			return r;
692 		}
693 
694 		addRow(key, value);
695 
696 		return null;
697 	}
698 }
699 
700 /* __oOo__ */