1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package uk.ac.rdg.resc.jstyx.interloper;
30
31 import javax.swing.table.AbstractTableModel;
32 import java.util.Vector;
33
34 /***
35 * Table model for the StyxMon
36 * @todo Add a "hint" column containing info on what the message exchange is doing
37 *
38 * @author Jon Blower
39 * $Revision: 49 $
40 * $Date: 2005-02-28 12:53:47 +0000 (Mon, 28 Feb 2005) $
41 * $Log$
42 * Revision 1.3 2005/02/28 12:53:47 jonblower
43 * Improved message filtering
44 *
45 * Revision 1.2 2005/02/24 09:07:12 jonblower
46 * Added code to support filtering by pop-up menu
47 *
48 * Revision 1.1 2005/02/24 07:42:07 jonblower
49 * Initial import
50 *
51 */
52 class StyxMonTableModel extends AbstractTableModel
53 {
54
55 private final static String[] columnNames = {"Type", "Tag", "Filename",
56 "TMessage", "RMessage"};
57
58 private Vector rows;
59
60 private Vector filter;
61
62
63 private String filterFilename;
64
65 /***
66 * Creates a new StyxMonTableModel
67 */
68 public StyxMonTableModel()
69 {
70 this.rows = new Vector();
71 this.filter = null;
72 }
73
74 /***
75 * Required by AbstractTableModel. Gets the number of rows of data.
76 */
77 public int getRowCount()
78 {
79 if (this.filter == null)
80 {
81 return this.rows.size();
82 }
83 else
84 {
85 return this.filter.size();
86 }
87 }
88
89 /***
90 * Required by AbstractTableModel. Gets the number of columns of data.
91 */
92 public int getColumnCount()
93 {
94 return columnNames.length;
95 }
96
97 /***
98 * Required by AbstractTableModel. Gets the object at the given row and
99 * column.
100 * @return the data as a String
101 * @throws ArrayIndexOutOfBoundsException if the given row or column are
102 * out of range
103 */
104 public synchronized Object getValueAt(int row, int column)
105 {
106 return this.getRowData(row, column, false)[column];
107 }
108
109 /***
110 * Sets the cell at the given row and column to the given value, which must
111 * be a string or a ClassCastException will be thrown
112 * @throws ArrayIndexOutOfBoundsException if the given row or column
113 * are out of range.
114 * @throws ClassCastException if the given value was not a String
115 */
116 public synchronized void setValueAt(Object value, int row, int column)
117 {
118 String[] s = this.getRowData(row, column, true);
119 s[column] = (String)value;
120 this.fireTableCellUpdated(row, column);
121 }
122
123 /***
124 * Gets the String array at the given row in the data model and also checks
125 * that the given column index is valid. If ignoreFilter is true, the filter
126 * will be ignored and the real data from the data model will be returned
127 * @throws ArrayIndexOutOfBoundsException if the given row or column
128 * are out of range
129 */
130 private synchronized String[] getRowData(int row, int column, boolean ignoreFilter)
131 {
132 if (column > this.columnNames.length - 1)
133 {
134 throw new ArrayIndexOutOfBoundsException("The column index was out of range");
135 }
136 int realRow;
137 if (ignoreFilter || this.filter == null)
138 {
139 realRow = row;
140 }
141 else
142 {
143
144 Integer intRow = (Integer)this.filter.get(row);
145 if (intRow == null)
146 {
147 throw new ArrayIndexOutOfBoundsException("The row index was out of range");
148 }
149 realRow = intRow.intValue();
150 }
151 String[] rowData = (String[])this.rows.get(realRow);
152 if (rowData == null)
153 {
154 throw new ArrayIndexOutOfBoundsException("The row index was out of range");
155 }
156 return rowData;
157 }
158
159 /***
160 * @return the heading for the column with the given index, or the empty
161 * string if the given column is out of range
162 */
163 public String getColumnName(int column)
164 {
165 if (column > this.columnNames.length - 1)
166 {
167 return "";
168 }
169 return this.columnNames[column];
170 }
171
172 /***
173 * @return the class of data in the given column (always String)
174 */
175 public Class getColumnClass(int columnIndex)
176 {
177 return String.class;
178 }
179
180 /***
181 * Adds a row to the end of the data model
182 */
183 public synchronized void addRow()
184 {
185 this.rows.add(new String[this.columnNames.length]);
186
187
188 int newRowIndex = this.rows.size() - 1;
189 this.fireTableRowsInserted(newRowIndex, newRowIndex);
190 }
191
192 /***
193 * Adds data when a Tmessage arrives. Checks to see if the data should be
194 * included in the current filtered view. The row will have already been
195 * created by this point.
196 */
197 public synchronized void addTMessageData(int row, String messageName,
198 int tag, String filename, String message)
199 {
200 this.setValueAt(messageName, row, 0);
201 this.setValueAt("" + tag, row, 1);
202 this.setValueAt(filename, row, 2);
203
204 if (this.filter != null && filename.equals(this.filterFilename))
205 {
206 this.filter.add(new Integer(row));
207 }
208 this.setValueAt(message, row, 3);
209 }
210
211 /***
212 * @return true if the given row contains a message pair (i.e. both a
213 * Tmessage and an Rmessage). Used by the StyxMonTableCellRenderer.
214 */
215 public boolean containsMessagePair(int row)
216 {
217 String[] rowData = this.getRowData(row, 0, false);
218
219 if (rowData[4] == null || rowData[4].equalsIgnoreCase(""))
220 {
221 return false;
222 }
223 return true;
224 }
225
226 /***
227 * @return true if the row contains an Rerror message. Used by the
228 * StyxMonTableCellRenderer. Simply looks to see if the contents of the
229 * Rmessage column start with "ERROR" (not the best way perhaps as it relies
230 * on the output of RerrorMessage.getFriendlyString()).
231 */
232 public boolean containsError(int row)
233 {
234 String[] rowData = this.getRowData(row, 0, false);
235
236 if (rowData[4] == null)
237 {
238 return false;
239 }
240 return rowData[4].startsWith("ERROR");
241 }
242
243 /***
244 * Presents a view of the data that only includes rows that contain
245 * the given filename. Does not affect the actual data and can be undone
246 * with this.showAllData().
247 */
248 public synchronized void filterByFilename(String filename)
249 {
250 this.filterFilename = filename.trim();
251 this.filter = new Vector();
252
253 for (int i = 0; i < this.rows.size(); i++)
254 {
255 String[] rowData = this.getRowData(i, 0, true);
256 if (rowData[2].equals(this.filterFilename.trim()))
257 {
258 this.filter.add(new Integer(i));
259 }
260 }
261 this.fireTableDataChanged();
262 }
263
264 /***
265 * Removes any filters, allowing all the data in the model to be displayed
266 */
267 public synchronized void showAllData()
268 {
269 this.filter = null;
270 this.fireTableDataChanged();
271 }
272
273 /***
274 * @return true if the data model is currently filtered
275 */
276 public boolean isFiltered()
277 {
278 return (this.filter != null);
279 }
280
281 }