View Javadoc

1   /*
2    * Copyright (c) 2005 The University of Reading
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    * 1. Redistributions of source code must retain the above copyright
9    *    notice, this list of conditions and the following disclaimer.
10   * 2. Redistributions in binary form must reproduce the above copyright
11   *    notice, this list of conditions and the following disclaimer in the
12   *    documentation and/or other materials provided with the distribution.
13   * 3. Neither the name of the University of Reading, nor the names of the
14   *    authors or contributors may be used to endorse or promote products
15   *    derived from this software without specific prior written permission.
16   * 
17   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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"}; //, "Hint"};
57          
58      private Vector rows; // Vector of String arrays containing the actual
59                           // underlying data (one String array per row)
60      private Vector filter; // Contains the indices of all the rows in the "rows"
61                             // Vector that are visible. If this is null, all the
62                             // rows will be visible
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             // The data are filtered. Get the index of the real row
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         // Notify all listeners that a row has been inserted. If we do not do 
187         // this, the StyxMon GUI will not be updated
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         // Now check to see if this should be included in the filter
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         // If the "Rmessage" column is empty, return false
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         // If the "Rmessage" column is empty, return false
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         // Search through all the rows to find the rows that contain this filename
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 }