1 /***
2 * TransposableTableModel.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.table;
27
28 import java.util.Arrays;
29
30 import javax.swing.table.AbstractTableModel;
31 import javax.swing.table.TableModel;
32
33 /***
34 * This TableModel implementation enables to transpose another TableModel. It is
35 * to be used in conjunction with a JTransposableTable to ensure the cells are
36 * correctly rendered and edited.
37 *
38 * @author $Author: dbregeon $
39 * @version $Revision: 1.1 $
40 */
41 public class TransposableTableModel extends AbstractTableModel {
42
43 /***
44 * When this policy is used, the column names disappear in the
45 * transposition.
46 */
47 public static final int IGNORE_COLUMN_NAMES = 0;
48
49 /***
50 * When this policy is used, the column names form the first column in the
51 * transposition.
52 */
53 public static final int USE_COLUMN_NAMES = 1;
54
55 /***
56 * When this policy is used, the first row provides the column names in the
57 * transposition.
58 */
59 public static final int FIRST_ROW_COLUMN_NAMES = 0;
60
61 /***
62 * When this policy is used, letters are used for column names in the
63 * transposition.
64 */
65 public static final int LETTERS_COLUMN_NAMES = 1;
66
67 /***
68 * When this policy is used, numbers are used for column names in the
69 * transposition.
70 */
71 public static final int NUMBERS_COLUMN_NAMES = 2;
72
73 /***
74 * An array of letters used to generate letter column names.
75 */
76 protected static final char[] LETTERS = new char[] { 'A', 'B', 'C', 'D',
77 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
78 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
79
80 /***
81 * Signals the current status of the Model.
82 */
83 private boolean transpose = false;
84
85 /***
86 * This variable controls whether column names are part of the transposition
87 * or not.
88 */
89 private int columnNamesPolicy = USE_COLUMN_NAMES;
90
91 /***
92 * This variable controls what the columns names are in the transposition.
93 */
94 private int transposedColumnNamesPolicy = FIRST_ROW_COLUMN_NAMES;
95
96 /***
97 * The TableModel transposed by this TransposableTableModel.
98 */
99 private TableModel underlyingModel = null;
100
101 /***
102 * Enables to transpose or untranspose the underlyingModel.
103 *
104 * @param b
105 * true to transpose the underlyingModel. false otherwise.
106 */
107 public void setTranspose(boolean b) {
108 if (this.transpose != b) {
109 this.transpose = b;
110 fireTableStructureChanged();
111 }
112 }
113
114 /***
115 * Gives access to the current status of the TransposableTableModel.
116 *
117 * @return true if the underlyingModel is transposed. false otherwise.
118 */
119 public boolean getTranspose() {
120 return this.transpose;
121 }
122
123 /***
124 * Enables to change the policy regarding the transposition of the column
125 * names.
126 *
127 * @param policy
128 * the new policy.
129 */
130 public void setColumnNamesPolicy(int policy) {
131 if ((policy == IGNORE_COLUMN_NAMES) || (policy == USE_COLUMN_NAMES)) {
132 this.columnNamesPolicy = policy;
133 }
134 }
135
136 /***
137 * Gives access to the current column names' policy.
138 *
139 * @return the current column names' policy.
140 */
141 public int getColumnNamesPolicy() {
142 return this.columnNamesPolicy;
143 }
144
145 /***
146 *
147 * @param policy
148 */
149 public void setTransposedColumnNamesPolicy(int policy) {
150 if ((policy == FIRST_ROW_COLUMN_NAMES)
151 || (policy == LETTERS_COLUMN_NAMES)
152 || (policy == NUMBERS_COLUMN_NAMES)) {
153 this.transposedColumnNamesPolicy = policy;
154 }
155 }
156
157 /***
158 *
159 * @return the policy to transpose column names.
160 */
161 public int getTransposedColumnNamesPolicy() {
162 return this.transposedColumnNamesPolicy;
163 }
164
165 /***
166 * Enables to change the underlyingModel that is transposed by this
167 * TransposableTableModel.
168 *
169 * @param model
170 * the TableModel to transpose.
171 */
172 public void setUnderlyingModel(TableModel model) {
173 this.underlyingModel = model;
174 fireTableStructureChanged();
175 }
176
177 /***
178 * Gives access to the TableModel that is transposed by this
179 * TransposableTableModel.
180 *
181 * @return the transposed TableModel.
182 */
183 public TableModel getUnderlyingModel() {
184 return this.underlyingModel;
185 }
186
187 /***
188 * @see javax.swing.table.TableModel#getRowCount()
189 */
190 public int getRowCount() {
191 int result = 0;
192 if (this.underlyingModel != null) {
193 if (this.transpose) {
194 if (this.transposedColumnNamesPolicy == FIRST_ROW_COLUMN_NAMES) {
195 result = this.underlyingModel.getColumnCount() - 1;
196 } else {
197 result = this.underlyingModel.getColumnCount();
198 }
199 } else {
200 result = this.underlyingModel.getRowCount();
201 }
202 }
203 return result;
204 }
205
206 /***
207 * @see javax.swing.table.TableModel#getColumnCount()
208 */
209 public int getColumnCount() {
210 int result = 0;
211 if (this.underlyingModel != null) {
212 if (this.transpose) {
213 result = this.underlyingModel.getRowCount() - 1
214 + this.columnNamesPolicy;
215 } else {
216 result = this.underlyingModel.getColumnCount();
217 }
218 }
219 return result;
220 }
221
222 /***
223 * @see javax.swing.table.TableModel#getValueAt(int, int)
224 */
225 public Object getValueAt(int rowIndex, int columnIndex) {
226 Object result = null;
227 if (this.underlyingModel != null) {
228 if (this.transpose) {
229 int offset = ((this.transposedColumnNamesPolicy == FIRST_ROW_COLUMN_NAMES) ? 1
230 : 0);
231 if (columnIndex < this.columnNamesPolicy) {
232 result = this.underlyingModel.getColumnName(rowIndex
233 + offset);
234 } else {
235 result = this.underlyingModel.getValueAt(columnIndex
236 + this.columnNamesPolicy, rowIndex + offset);
237 }
238 } else {
239 result = this.underlyingModel.getValueAt(rowIndex, columnIndex);
240 }
241 }
242 return result;
243 }
244
245 /***
246 * @see javax.swing.table.TableModel#getColumnClass(int)
247 */
248 public Class getColumnClass(int columnIndex) {
249 Class result = null;
250 if (this.transpose) {
251 result = TransposedValue.class;
252 } else {
253 if (this.underlyingModel != null) {
254 result = this.underlyingModel.getColumnClass(columnIndex);
255 }
256 }
257 return result;
258 }
259
260 /***
261 * @see javax.swing.table.TableModel#getColumnName(int)
262 */
263 public String getColumnName(int column) {
264 String result = null;
265 if (this.underlyingModel != null) {
266 if (this.transpose) {
267 if (this.transposedColumnNamesPolicy == FIRST_ROW_COLUMN_NAMES) {
268 if (column < this.columnNamesPolicy) {
269 result = this.underlyingModel.getColumnName(column);
270 } else {
271 Object value = this.underlyingModel.getValueAt(column
272 - this.columnNamesPolicy, 0);
273 if (value != null) {
274 result = value.toString();
275 }
276 }
277 } else if (this.transposedColumnNamesPolicy == LETTERS_COLUMN_NAMES) {
278 result = getColumnLetters(column);
279 } else if (this.transposedColumnNamesPolicy == NUMBERS_COLUMN_NAMES) {
280 result = Integer.toString(column + 1);
281 }
282 } else {
283 result = this.underlyingModel.getColumnName(column);
284 }
285 }
286 return result;
287 }
288
289 /***
290 * @see javax.swing.table.TableModel#isCellEditable(int, int)
291 */
292 public boolean isCellEditable(int rowIndex, int columnIndex) {
293 boolean result = false;
294 if (this.underlyingModel != null) {
295 if (this.transpose) {
296 int offset = ((this.transposedColumnNamesPolicy == FIRST_ROW_COLUMN_NAMES) ? 1
297 : 0);
298 if (columnIndex >= this.columnNamesPolicy) {
299 result = this.underlyingModel.isCellEditable(columnIndex
300 + this.columnNamesPolicy, rowIndex + offset);
301 }
302 } else {
303 result = this.underlyingModel.isCellEditable(rowIndex,
304 columnIndex);
305 }
306 }
307 return result;
308 }
309
310 /***
311 * @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
312 */
313 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
314 if (this.underlyingModel != null) {
315 int offset = ((this.transposedColumnNamesPolicy == FIRST_ROW_COLUMN_NAMES) ? 1
316 : 0);
317 if (this.transpose) {
318 if (columnIndex >= this.columnNamesPolicy) {
319 this.underlyingModel.setValueAt(aValue, columnIndex
320 + this.columnNamesPolicy, rowIndex + offset);
321 }
322 } else {
323 this.underlyingModel.setValueAt(aValue, rowIndex, columnIndex);
324 }
325 }
326 }
327
328 protected String getColumnLetters(int column) {
329 char[] letters = new char[column / LETTERS.length + 1];
330 Arrays.fill(letters, LETTERS[column % LETTERS.length]);
331 return new String(letters);
332 }
333
334 /***
335 * A Place holder class to enable to define special renderers in the
336 * transposed tables.
337 *
338 * @author $Author: dbregeon $
339 * @version $Revision: 1.1 $
340 */
341 public static interface TransposedValue {
342
343 }
344 }