Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/geotools/gui/swing/LoggingTableModel.java


1   /*
2    * -*- mode: java; c-basic-indent: 4; indent-tabs-mode: nil -*-
3    * :indentSize=4:noTabs=true:tabSize=4:indentOnTab=true:indentOnEnter=true:mode=java:
4    * ex: set tabstop=4 expandtab:
5    *
6    * MrPostman - webmail <-> email gateway
7    * Copyright (C) 2002-2003 MrPostman Development Group
8    * Projectpage: http://mrbook.org/mrpostman/
9    *
10   *
11   * This program is free software; you can redistribute it and/or modify
12   * it under the terms of the GNU General Public License as published by
13   * the Free Software Foundation; either version 2 of the License, or
14   * (at your option) any later version.
15   *
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * In particular, this implies that users are responsible for
21   * using MrPostman after reading the terms and conditions given
22   * by their web-mail provider.
23   *
24   * You should have received a copy of the GNU General Public License
25   * Named LICENSE in the base directory of this distribution,
26   * if not, write to the Free Software
27   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28   */
29  
30  /*
31   * Geotools - OpenSource mapping toolkit
32   * (C) 2002, Centre for Computational Geography
33   * (C) 2002, Institut de Recherche pour le Développement
34   *
35   *    This library is free software; you can redistribute it and/or
36   *    modify it under the terms of the GNU Lesser General Public
37   *    License as published by the Free Software Foundation; either
38   *    version 2.1 of the License, or (at your option) any later version.
39   *
40   *    This library is distributed in the hope that it will be useful,
41   *    but WITHOUT ANY WARRANTY; without even the implied warranty of
42   *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43   *    Lesser General Public License for more details.
44   *
45   *    You should have received a copy of the GNU Lesser General Public
46   *    License along with this library; if not, write to the Free Software
47   *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
48   *
49   *
50   * Contacts:
51   *     UNITED KINGDOM: James Macgill
52   *             mailto:j.macgill@geog.leeds.ac.uk
53   *
54   *     FRANCE: Surveillance de l'Environnement Assistée par Satellite
55   *             Institut de Recherche pour le Développement / US-Espace
56   *             mailto:seasnet@teledetection.fr
57   *
58   *     CANADA: Observatoire du Saint-Laurent
59   *             Institut Maurice-Lamontagne
60   *             mailto:osl@osl.gc.ca
61   */
62  package org.geotools.gui.swing;
63  
64  
65  // Resources
66  import org.geotools.resources.XArray;
67  import org.geotools.resources.gui.ResourceKeys;
68  import org.geotools.resources.gui.Resources;
69  
70  import java.awt.EventQueue;
71  
72  import java.text.DateFormat;
73  
74  
75  // Formatting
76  import java.util.Date;
77  import java.util.LinkedHashMap;
78  // Collections
79  import java.util.Map;
80  import java.util.logging.Handler;
81  // Logging
82  import java.util.logging.Level;
83  import java.util.logging.LogRecord;
84  import java.util.logging.SimpleFormatter;
85  
86  import javax.swing.event.EventListenerList;
87  import javax.swing.event.TableModelEvent;
88  import javax.swing.event.TableModelListener;
89  // Table model
90  import javax.swing.table.TableModel;
91  
92  
93  /**
94   * A logging {@link Handler} storing {@link LogRecords} as a {@link TableModel}.
95   * This model is used by {@link LoggingPanel} for displaying logging messages in
96   * a {@link javax.swing.JTable}.
97   *
98   * @version $Id: LoggingTableModel.java,v 1.5 2003/02/09 23:38:11 lbruand Exp $
99   * @author Martin Desruisseaux
100  */
101 final class LoggingTableModel extends Handler implements TableModel {
102     public static final String CVSID = "$Id: LoggingTableModel.java,v 1.5 2003/02/09 23:38:11 lbruand Exp $";
103 
104     /**
105      * Resource keys for column names.
106      */
107     private static final int[] COLUMN_NAMES = new int[] {
108             ResourceKeys.LOGGER, ResourceKeys.CLASS, ResourceKeys.METHOD, ResourceKeys.TIME_OF_DAY, ResourceKeys.LEVEL,
109             ResourceKeys.MESSAGE
110         };
111 
112     /**
113      * The last {@link LogRecord}s stored. This array will grows as needed up to
114      * {@link #capacity}. Once the maximal capacity is reached, early records
115      * are discarted.
116      */
117     private LogRecord[] records = new LogRecord[16];
118 
119     /**
120      * The maximum amount of records that can be stored in this logging panel.
121      * If more than {@link #capacity} messages are logged, early messages will
122      * be discarted.
123      */
124     private int capacity = 500;
125 
126     /**
127      * The total number of logging messages published by this panel. This number may be
128      * greater than the amount of {@link LogRecord} actually memorized, since early records
129      * may have been discarted. The slot in <code>records</code> where to write the next
130      * message can be computed by <code>recordCount % capacity</code>.
131      */
132     private int recordCount;
133 
134     /**
135      * String representations of latest required records. Keys are {@link LogRecord} objects
136      * and values are <code>String[]</code>. This is a cache for faster rendering.
137      */
138     private final Map cache = new LinkedHashMap() {
139             protected boolean removeEldestEntry(final Map.Entry eldest) {
140                 return size() >= Math.min(capacity, 80);
141             }
142         };
143 
144     /**
145      * The list of registered listeners.
146      */
147     private final EventListenerList listenerList = new EventListenerList();
148 
149     /**
150      * The format to use for formatting time.
151      */
152     private final DateFormat dateFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM);
153 
154     /**
155      * Construct the handler.
156      */
157     public LoggingTableModel() {
158         setLevel(Level.CONFIG);
159         setFormatter(new SimpleFormatter());
160     }
161 
162     /**
163      * Returns the capacity. This is the maximum number of {@link LogRecord}s this handler
164      * can memorize. If more messages are logged, then the oldiest messages will be discarted.
165      */
166     public int getCapacity() {
167         return capacity;
168     }
169 
170     /**
171      * Set the capacity. This is the maximum number of {@link LogRecord}s this handler can
172      * memorize. If more messages are logged, then the oldiest messages will be discarted.
173      */
174     public synchronized void setCapacity(final int capacity) {
175         if (recordCount != 0) {
176             throw new IllegalStateException("Not yet implemented.");
177         }
178         this.capacity = capacity;
179     }
180 
181     /**
182      * Publish a {@link LogRecord}. If the maximal capacity has been reached,
183      * the oldiest record will be discarted.
184      */
185     public synchronized void publish(final LogRecord record) {
186         if (!isLoggable(record)) {
187             return;
188         }
189         final int nextSlot = recordCount % capacity;
190 
191         if (nextSlot >= records.length) {
192             records = (LogRecord[]) XArray.resize(records, Math.min(records.length * 2, capacity));
193         }
194         records[nextSlot] = record;
195         final TableModelEvent event;
196 
197         if (++recordCount <= capacity) {
198             event = new TableModelEvent(this, nextSlot, nextSlot, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT);
199         } else {
200             event = new TableModelEvent(this, 0, capacity - 1, TableModelEvent.ALL_COLUMNS, TableModelEvent.UPDATE);
201         }
202 
203         //
204         // Notify all listeners that a record has been added.
205         //
206         EventQueue.invokeLater(new Runnable() {
207                 public void run() {
208                     fireTableChanged(event);
209                 }
210             });
211     }
212 
213     /**
214      * Returns the log record for the specified row.
215      *
216      * @param row The row in the table. This is the visible row,
217      *            not the record number from the first record.
218      */
219     public synchronized LogRecord getLogRecord(int row) {
220         /* assert row < getRowCount(); */
221         if (recordCount > capacity) {
222             row += (recordCount % capacity);
223             row %= capacity;
224         }
225         return records[row];
226     }
227 
228     /**
229      * Returns the number of columns in the model.
230      */
231     public int getColumnCount() {
232         return COLUMN_NAMES.length;
233     }
234 
235     /**
236      * Returns the number of rows in the model.
237      */
238     public synchronized int getRowCount() {
239         return Math.min(recordCount, capacity);
240     }
241 
242     /**
243      * Returns the most specific superclass for all the cell values in the column.
244      */
245     public Class getColumnClass(final int columnIndex) {
246         return String.class;
247     }
248 
249     /**
250      * Returns the name of the column at <code>columnIndex</code>.
251      */
252     public String getColumnName(final int columnIndex) {
253         return Resources.format(COLUMN_NAMES[columnIndex]);
254     }
255 
256     /**
257      * Returns the value for the cell at <code>columnIndex</code> and <code>rowIndex</code>.
258      */
259     public synchronized Object getValueAt(final int rowIndex, final int columnIndex) {
260         final LogRecord record = getLogRecord(rowIndex);
261         String[] row = (String[]) cache.get(record);
262 
263         if (row == null) {
264             row = new String[getColumnCount()];
265             row[0] = record.getLoggerName();
266             row[1] = getShortClassName(record.getSourceClassName());
267             row[2] = record.getSourceMethodName();
268             row[3] = dateFormat.format(new Date(record.getMillis()));
269             row[4] = record.getLevel().getLocalizedName();
270             row[5] = getFormatter().formatMessage(record);
271             cache.put(record, row);
272             /*assert cache.size() <= capacity;*/
273         }
274         return row[columnIndex];
275     }
276 
277     /**
278      * Returns the class name in a shorter form (without package).
279      */
280     private static String getShortClassName(String name) {
281         final int dot = name.lastIndexOf('.');
282 
283         if (dot >= 0) {
284             name = name.substring(dot + 1);
285         }
286         return name.replace('$', '.');
287     }
288 
289     /**
290      * Do nothing since cells are not editable.
291      */
292     public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
293     }
294 
295     /**
296      * Returns <code>false</code> since cells are not editable.
297      */
298     public boolean isCellEditable(int rowIndex, int columnIndex) {
299         return false;
300     }
301 
302     /**
303      * Adds a listener that is notified each time a change to the data model occurs.
304      */
305     public void addTableModelListener(final TableModelListener listener) {
306         listenerList.add(TableModelListener.class, listener);
307     }
308 
309     /**
310      * Removes a listener from the list that is notified each time a change occurs.
311      */
312     public void removeTableModelListener(final TableModelListener listener) {
313         listenerList.remove(TableModelListener.class, listener);
314     }
315 
316     /**
317      * Forwards the given notification event to all {@link TableModelListeners}.
318      */
319     private void fireTableChanged(final TableModelEvent event) {
320         final Object[] listeners = listenerList.getListenerList();
321 
322         for (int i = listeners.length - 2; i >= 0; i -= 2) {
323             if (listeners[i] == TableModelListener.class) {
324                 ((TableModelListener) listeners[i + 1]).tableChanged(event);
325             }
326         }
327     }
328 
329     /**
330      * Flush any buffered output.
331      */
332     public void flush() {
333     }
334 
335     /**
336      * Close the <code>Handler</code> and free all associated resources.
337      */
338     public void close() {
339     }
340 }