View Javadoc

1   /***
2    * JReportTable.java
3    *
4    * This file is part of the creme library.
5    * The creme library intends to ease the development effort of large
6    * applications by providing easy to use support classes.
7    *
8    * Copyright (C) 2003 Denis Bregeon
9    *
10   * This library is free software; you can redistribute it and/or
11   * modify it under the terms of the GNU Lesser General Public
12   * License as published by the Free Software Foundation; either
13   * version 2.1 of the License, or (at your option) any later version.
14   *
15   * This library is distributed in the hope that it will be useful,
16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   * Lesser General Public License for more details.
19   *
20   * You should have received a copy of the GNU Lesser General Public
21   * License along with this library; if not, write to the Free Software
22   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23   *
24   * contact information: dbregeon@sourceforge.net
25   */
26  package org.jcreme.swing.reporting;
27  
28  import java.util.HashSet;
29  
30  import javax.swing.ImageIcon;
31  import javax.swing.table.JTableHeader;
32  import javax.swing.table.TableColumn;
33  import javax.swing.table.TableColumnModel;
34  import javax.swing.table.TableModel;
35  
36  import org.jcreme.enumerations.ComparatorType;
37  import org.jcreme.enumerations.SortOrder;
38  import org.jcreme.reporting.Report;
39  import org.jcreme.swing.table.JColoredTable;
40  import org.jcreme.swing.table.SortableColumnHeaderMouseListener;
41  import org.jcreme.swing.table.SortableColumnTableHeaderRenderer;
42  import org.jcreme.swing.table.SortableTableColumn;
43  import org.jcreme.swing.table.TableColumnOrderEvent;
44  import org.jcreme.swing.table.TableColumnOrderListener;
45  import org.jcreme.swing.table.columnmodel.EditableTableColumnModel;
46  
47  /***
48   * This class provides all the defaults to easily integrate reports. It enables
49   * to display a sortable JTable from a report without efforts.
50   * 
51   * @author $Author: dbregeon $
52   * @version $Revision: 1.1 $
53   */
54  public class JReportTable extends JColoredTable {
55      /***
56       * The icon displayed in the column header when sort is ASCENDING.
57       */
58      public static final ImageIcon ARROW_UP = new ImageIcon(JReportTable.class
59              .getClassLoader().getResource("images/uparrow.gif"));
60  
61      /***
62       * The icon displayed in the column header when sort is DESCENDING.
63       */
64      public static final ImageIcon ARROW_DOWN = new ImageIcon(JReportTable.class
65              .getClassLoader().getResource("images/downarrow.gif"));
66  
67      /***
68       * The underlying report for this table.
69       */
70      private Report report = null;
71  
72      /***
73       * The columns currently in use in the sort.
74       */
75      private final HashSet sortedColumns = new HashSet();
76  
77      /***
78       * The listener for the SortableTableColumns to react to changes in a column
79       * order.
80       */
81      private final TableColumnOrderListener tableColumnOrderListener = new TableColumnOrderListener() {
82          public void tableColumnOrderChanged(TableColumnOrderEvent e) {
83              orderChanged((SortableTableColumn) e.getSource());
84              sort();
85          }
86      };
87  
88      /***
89       * The listener to detect clicks on the JTableHeader to apply sort on the
90       * clicked column.
91       */
92      private final SortableColumnHeaderMouseListener headerColumnListener = new SortableColumnHeaderMouseListener();
93  
94      /***
95       * This method enables to create the default TableModel for this Table.
96       * 
97       * @return either the superclass result for createDefaultDataModel or a
98       *         ReportTableModel instance if report is set.
99       */
100     protected TableModel createDefaultDataModel() {
101         TableModel result = null;
102         if (this.report != null) {
103             result = new ReportTableModel(this.report);
104         } else {
105             return super.createDefaultDataModel();
106         }
107         return result;
108     }
109 
110     /***
111      * This method enabled to create the default TableColumnModel for this
112      * Table.
113      * 
114      * @return either the superclass result for createDefaultColumnModel or an
115      *         EditableTableColumnModel instance if report is set.
116      */
117     protected TableColumnModel createDefaultColumnModel() {
118         return new EditableTableColumnModel();
119     }
120 
121     /***
122      * This method enables to set the ColumnModel. If the new model contains
123      * SortableTableColumn, listeners and renderers are set.
124      * 
125      * @param model
126      *            the new column model.
127      */
128     public void setColumnModel(TableColumnModel model) {
129         TableColumnModel cm = getColumnModel();
130         TableColumn current = null;
131         int count = 0;
132         while ((cm != null) && (count < cm.getColumnCount())) {
133             current = cm.getColumn(count);
134             if (current instanceof SortableTableColumn) {
135                 ((SortableTableColumn) current)
136                         .removeTableColumnOrderListener(this.tableColumnOrderListener);
137                 count++;
138             }
139         }
140         super.setColumnModel(model);
141         cm = getColumnModel();
142         count = 0;
143         while ((cm != null) && (count < cm.getColumnCount())) {
144             current = cm.getColumn(count);
145             if (current instanceof SortableTableColumn) {
146                 prepareColumn((SortableTableColumn) current);
147                 orderChanged((SortableTableColumn) current);
148             }
149             count++;
150         }
151         sort();
152     }
153 
154     /***
155      * This method enables to set the JTableHeader. Listeners are added to the
156      * new header.
157      * 
158      * @param header
159      *            the new JTableHeader.
160      */
161     public void setTableHeader(JTableHeader header) {
162         if (getTableHeader() != null) {
163             getTableHeader().removeMouseListener(this.headerColumnListener);
164         }
165         super.setTableHeader(header);
166         if (getTableHeader() != null) {
167             getTableHeader().addMouseListener(this.headerColumnListener);
168         }
169     }
170 
171     /***
172      * This method creates the columns and adds them to the TableColumnModel,
173      * based on the TableModel. This method creates SortableTableColumns
174      * whenever at least one ComparatorType is associated to the column's class.
175      */
176     public void createDefaultColumnsFromModel() {
177         TableModel m = getModel();
178         if (m != null) {
179             // Remove any current columns
180             TableColumnModel cm = getColumnModel();
181             while (cm.getColumnCount() > 0) {
182                 if (cm.getColumn(0) instanceof SortableTableColumn) {
183                     ((SortableTableColumn) cm.getColumn(0))
184                             .removeTableColumnOrderListener(this.tableColumnOrderListener);
185                 }
186                 cm.removeColumn(cm.getColumn(0));
187             }
188 
189             // Create new columns from the data model info
190             TableColumn newColumn = null;
191             SortableTableColumn newSortableColumn = null;
192             ComparatorType[] comparators = null;
193             Class columnClass = null;
194             String columnName = null;
195             for (int i = 0; i < m.getColumnCount(); i++) {
196                 columnClass = m.getColumnClass(i);
197                 columnName = m.getColumnName(i);
198                 comparators = ComparatorType.getComparatorTypes(columnClass);
199                 if ((comparators != null) && (comparators.length > 0)) {
200                     newSortableColumn = new SortableTableColumn(i);
201                     prepareColumn(newSortableColumn);
202                     newSortableColumn
203                             .setComparator((Comparable.class.isAssignableFrom(m
204                                     .getColumnClass(i))) ? ComparatorType.DEFAULT
205                                     : comparators[0]);
206                     newSortableColumn.setColumnClass(columnClass);
207                     newColumn = newSortableColumn;
208                 } else {
209                     newColumn = new TableColumn(i);
210                 }
211                 newColumn.setIdentifier(columnName);
212                 newColumn.setHeaderValue(columnName);
213                 newColumn.setResizable(true);
214                 addColumn(newColumn);
215             }
216         }
217     }
218 
219     /***
220      * Creates a default JTableHeader. This method acts the same way as the
221      * super class' except that listeners are added to the new Header.
222      * 
223      * @return JTableHeader the header created for this table.
224      */
225     protected JTableHeader createDefaultTableHeader() {
226         if (super.getTableHeader() != null) {
227             super.getTableHeader().removeMouseListener(
228                     this.headerColumnListener);
229         }
230         JTableHeader header = super.createDefaultTableHeader();
231         header.addMouseListener(this.headerColumnListener);
232         return header;
233     }
234 
235     /***
236      * This method enables to set the report that will be presented in this
237      * Table.
238      * 
239      * @param r
240      *            the Report to present.
241      */
242     public void setReport(Report r) {
243         this.report = r;
244         getTableHeader().removeMouseListener(this.headerColumnListener);
245         setModel(createDefaultDataModel());
246         getTableHeader().addMouseListener(this.headerColumnListener);
247         sort();
248     }
249 
250     /***
251      * This method enables to access the Report presented in this Table.
252      * 
253      * @return the report presented.
254      */
255     public Report getReport() {
256         return this.report;
257     }
258 
259     /***
260      * This is a convenience method to apply the sort to the TableModel, from
261      * the sortable columns.
262      */
263     protected void sort() {
264         TableModel model = getModel();
265         if (model instanceof ReportTableModel) {
266             ((ReportTableModel) model)
267                     .sort((SortableTableColumn[]) this.sortedColumns
268                             .toArray(new SortableTableColumn[0]));
269         }
270     }
271 
272     /***
273      * This is a convenience method to handle column order changes.
274      * 
275      * @param column
276      *            the column for which order was changed.
277      */
278     protected void orderChanged(SortableTableColumn column) {
279         if (column.getOrder() != SortOrder.NONE) {
280             this.sortedColumns.add(column);
281         } else {
282             this.sortedColumns.remove(column);
283         }
284     }
285 
286     /***
287      * This is a convenience method that installs listeners and header renderer
288      * on SortableTableColumns.
289      * 
290      * @param column
291      *            the column on which to install listeners and renderer.
292      */
293     protected void prepareColumn(SortableTableColumn column) {
294         column.setHeaderRenderer(new SortableColumnTableHeaderRenderer(column,
295                 ARROW_DOWN, ARROW_UP));
296         column.addTableColumnOrderListener(this.tableColumnOrderListener);
297     }
298 }