1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package net.sf.xframe.swing.table;
22
23 import java.util.Enumeration;
24 import java.util.NoSuchElementException;
25
26 import javax.swing.ListSelectionModel;
27 import javax.swing.event.TableColumnModelListener;
28 import javax.swing.table.TableColumn;
29 import javax.swing.table.TableColumnModel;
30
31 import net.sf.xframe.swing.JXTable;
32
33
34 /***
35 * Column model of all locked and scrollable colums.
36 */
37 public class JXTableColumnModel implements TableColumnModel {
38
39 /*** the JXTable where this column model is currently used. */
40 private final JXTable table;
41
42 /*** Column model of locked table. */
43 private TableColumnModel lockedColumnModel;
44
45 /*** Column model of scrollable table. */
46 private TableColumnModel scrollColumnModel;
47
48 /***
49 * Constructor.
50 *
51 * @param theTable the JXTable that uses this column model
52 * @param theLockedColumnModel column model of locked table
53 * @param theScrollColumnModel column model of scrollable table
54 */
55 public JXTableColumnModel(final JXTable theTable,
56 final TableColumnModel theLockedColumnModel,
57 final TableColumnModel theScrollColumnModel) {
58 lockedColumnModel = theLockedColumnModel;
59 this.table = theTable;
60 scrollColumnModel = theScrollColumnModel;
61 }
62
63 /***
64 * Convinience method to access the locked table from the JXTable.
65 *
66 * @return the locked table
67 */
68
69
70
71
72 /***
73 * Convinience method to access the scrollable table from the JXTable.
74 *
75 * @return the scrollable table
76 */
77
78
79
80
81 /***
82 * Convinience method to access the number of frozen columns.
83 *
84 * @return number of frozen columns
85 */
86 private int getFrozenColumns() {
87 return this.table.getFrozenColumns();
88 }
89
90 /***
91 * Returns the number of columns in the model.
92 * @return the number of columns in the model
93 */
94 public int getColumnCount() {
95 return lockedColumnModel.getColumnCount() + scrollColumnModel.getColumnCount() - 1;
96 }
97
98 /***
99 * Returns the width between the cells in each column.
100 * @return the margin, in pixels, between the cells
101 */
102 public int getColumnMargin() {
103 return lockedColumnModel.getColumnMargin();
104 }
105
106 /***
107 * Returns the number of selected columns.
108 *
109 * @return the number of selected columns; or 0 if no columns are selected
110 */
111 public int getSelectedColumnCount() {
112 return lockedColumnModel.getSelectedColumnCount() + scrollColumnModel.getSelectedColumnCount();
113 }
114
115 /***
116 * Returns the total width of all the columns.
117 * @return the total computed width of all columns
118 */
119 public int getTotalColumnWidth() {
120 return lockedColumnModel.getTotalColumnWidth() + scrollColumnModel.getTotalColumnWidth();
121 }
122
123 /***
124 * Returns true if columns may be selected.
125 * @return true if columns may be selected
126 * @see #setColumnSelectionAllowed
127 */
128 public boolean getColumnSelectionAllowed() {
129 return lockedColumnModel.getColumnSelectionAllowed();
130 }
131
132 /***
133 * Returns the index of the column that lies on the
134 * horizontal point, <code>xPosition</code>;
135 * or -1 if it lies outside the any of the column's bounds.
136 *
137 * In keeping with Swing's separable model architecture, a
138 * TableColumnModel does not know how the table columns actually appear on
139 * screen. The visual presentation of the columns is the responsibility
140 * of the view/controller object using this model (typically JTable). The
141 * view/controller need not display the columns sequentially from left to
142 * right. For example, columns could be displayed from right to left to
143 * accomodate a locale preference or some columns might be hidden at the
144 * request of the user. Because the model does not know how the columns
145 * are laid out on screen, the given <code>xPosition</code> should not be
146 * considered to be a coordinate in 2D graphics space. Instead, it should
147 * be considered to be a width from the start of the first column in the
148 * model. If the column index for a given X coordinate in 2D space is
149 * required, <code>JTable.columnAtPoint</code> can be used instead.
150 *
151 * @return the index of the column; or -1 if no column is found
152 * @see javax.swing.JTable#columnAtPoint
153 */
154 public int[] getSelectedColumns() {
155 final int[] lockedSelectedColumns = lockedColumnModel.getSelectedColumns();
156 final int[] scrollSelectedColumns = scrollColumnModel.getSelectedColumns();
157 final int[] selectedColumns = new int[lockedSelectedColumns.length + scrollSelectedColumns.length];
158 for (int i = 0; i < lockedSelectedColumns.length; i++) {
159 selectedColumns[i] = lockedSelectedColumns[i];
160 }
161 for (int i = 0; i < scrollSelectedColumns.length; i++) {
162 selectedColumns[lockedSelectedColumns.length + i] = scrollSelectedColumns[i];
163 }
164 return selectedColumns;
165 }
166
167 /***
168 * @see javax.swing.table.TableColumnModel#getColumnIndexAtX(int)
169 */
170 public int getColumnIndexAtX(final int xPosition) {
171 if (xPosition <= lockedColumnModel.getTotalColumnWidth()) {
172 return lockedColumnModel.getColumnIndexAtX(xPosition);
173 } else {
174 return getFrozenColumns()
175 + scrollColumnModel.getColumnIndexAtX(xPosition - lockedColumnModel.getTotalColumnWidth());
176 }
177 }
178
179 /***
180 * Sets the <code>TableColumn</code>'s column margin to
181 * <code>newMargin</code>. This method posts
182 * a <code>columnMarginChanged</code> event to its listeners.
183 *
184 * @param newMargin the width, in pixels, of the new column margins
185 * @see #getColumnMargin
186 */
187 public void setColumnMargin(final int newMargin) {
188 lockedColumnModel.setColumnMargin(newMargin);
189 scrollColumnModel.setColumnMargin(newMargin);
190 }
191
192 /***
193 * Moves the column and its header at <code>columnIndex</code> to
194 * <code>newIndex</code>. The old column at <code>columnIndex</code>
195 * will now be found at <code>newIndex</code>. The column that used
196 * to be at <code>newIndex</code> is shifted left or right
197 * to make room. This will not move any columns if
198 * <code>columnIndex</code> equals <code>newIndex</code>. This method
199 * posts a <code>columnMoved</code> event to its listeners.
200 *
201 * @param columnIndex the index of column to be moved
202 * @param newIndex index of the column's new location
203 * @exception IllegalArgumentException if <code>columnIndex</code> or
204 * <code>newIndex</code>
205 * are not in the valid range
206 */
207 public void moveColumn(final int columnIndex, final int newIndex) throws IllegalArgumentException {
208 if (columnIndex < getFrozenColumns() && newIndex < getFrozenColumns()) {
209
210 lockedColumnModel.moveColumn(columnIndex, newIndex);
211 } else if (columnIndex < getFrozenColumns() && newIndex >= getFrozenColumns()) {
212
213 final TableColumn tableColumn = lockedColumnModel.getColumn(columnIndex);
214 lockedColumnModel.removeColumn(tableColumn);
215 scrollColumnModel.addColumn(tableColumn);
216 scrollColumnModel.moveColumn(scrollColumnModel.getColumnCount(), newIndex - getFrozenColumns());
217 } else if (columnIndex >= getFrozenColumns() && newIndex < getFrozenColumns()) {
218
219 final TableColumn tableColumn = scrollColumnModel.getColumn(columnIndex);
220 scrollColumnModel.removeColumn(tableColumn);
221 lockedColumnModel.addColumn(tableColumn);
222 lockedColumnModel.moveColumn(lockedColumnModel.getColumnCount(), newIndex);
223 } else {
224
225 scrollColumnModel.moveColumn(columnIndex, newIndex);
226 }
227 }
228
229 /***
230 * Sets whether the columns in this model may be selected.
231 * @param flag true if columns may be selected; otherwise false
232 * @see #getColumnSelectionAllowed
233 */
234 public void setColumnSelectionAllowed(final boolean flag) {
235 lockedColumnModel.setColumnSelectionAllowed(flag);
236 scrollColumnModel.setColumnSelectionAllowed(flag);
237 }
238
239 /***
240 * Returns the index of the first column in the table
241 * whose identifier is equal to <code>identifier</code>,
242 * when compared using <code>equals</code>.
243 *
244 * @param columnIdentifier the identifier object
245 * @return the index of the first table column
246 * whose identifier is equal to <code>identifier</code>
247 * @exception IllegalArgumentException if <code>identifier</code>
248 * is <code>null</code>, or no
249 * <code>TableColumn</code> has this
250 * <code>identifier</code>
251 * @see #getColumn
252 */
253 public int getColumnIndex(final Object columnIdentifier) throws IllegalArgumentException {
254 try {
255 return lockedColumnModel.getColumnIndex(columnIdentifier);
256 } catch (IllegalArgumentException e) {
257 return getFrozenColumns() + scrollColumnModel.getColumnIndex(columnIdentifier);
258 }
259 }
260
261 /***
262 * Returns an <code>Enumeration</code> of all the columns in the model.
263 * @return an <code>Enumeration</code> of all the columns in the model
264 */
265 public Enumeration getColumns() {
266 return new JXColumnsEnumeration();
267 }
268
269 /***
270 * Returns the current selection model.
271 *
272 * @return a <code>ListSelectionModel</code> object
273 * @see #setSelectionModel
274 */
275 public ListSelectionModel getSelectionModel() {
276 return lockedColumnModel.getSelectionModel();
277 }
278
279 /***
280 * Sets the selection model.
281 *
282 * @param newModel a <code>ListSelectionModel</code> object
283 * @see #getSelectionModel
284 */
285 public void setSelectionModel(final ListSelectionModel newModel) {
286 lockedColumnModel.setSelectionModel(newModel);
287 scrollColumnModel.setSelectionModel(newModel);
288 }
289
290 /***
291 * Adds a listener for table column model events.
292 *
293 * @param x a <code>TableColumnModelListener</code> object
294 */
295 public void addColumnModelListener(final TableColumnModelListener x) {
296 lockedColumnModel.addColumnModelListener(x);
297 scrollColumnModel.addColumnModelListener(x);
298
299 }
300
301 /***
302 * Removes a listener for table column model events.
303 *
304 * @param x a <code>TableColumnModelListener</code> object
305 */
306 public void removeColumnModelListener(final TableColumnModelListener x) {
307 lockedColumnModel.removeColumnModelListener(x);
308 scrollColumnModel.removeColumnModelListener(x);
309 }
310
311 /***
312 * Returns the <code>TableColumn</code> object for the column at
313 * <code>columnIndex</code>.
314 *
315 * @param columnIndex the index of the desired column
316 * @return the <code>TableColumn</code> object for
317 * the column at <code>columnIndex</code>
318 */
319 public TableColumn getColumn(final int columnIndex) {
320 if (columnIndex < getFrozenColumns()) {
321 return lockedColumnModel.getColumn(columnIndex);
322 } else {
323 return scrollColumnModel.getColumn(columnIndex - getFrozenColumns());
324 }
325 }
326
327 /***
328 * Appends <code>aColumn</code> to the end of the
329 * <code>tableColumns</code> array.
330 * This method posts a <code>columnAdded</code>
331 * event to its listeners.
332 *
333 * @param aColumn the <code>TableColumn</code> to be added
334 * @see #removeColumn
335 */
336 public void addColumn(final TableColumn aColumn) {
337 scrollColumnModel.addColumn(aColumn);
338
339 }
340
341 /***
342 * Deletes the <code>TableColumn</code> <code>column</code> from the
343 * <code>tableColumns</code> array. This method will do nothing if
344 * <code>column</code> is not in the table's column list.
345 * This method posts a <code>columnRemoved</code>
346 * event to its listeners.
347 *
348 * @param column the <code>TableColumn</code> to be removed
349 * @see #addColumn
350 */
351 public void removeColumn(final TableColumn column) {
352 lockedColumnModel.removeColumn(column);
353 scrollColumnModel.removeColumn(column);
354
355 }
356
357 /***
358 * Enumeration over all locked and scrollable colums.
359 */
360 private final class JXColumnsEnumeration implements Enumeration {
361
362 /*** Enumeration over locked columns. */
363 private Enumeration lockedEnumeration = lockedColumnModel.getColumns();
364
365 /*** Enumeration over scrollable columns. */
366 private Enumeration scrollEnumeration = scrollColumnModel.getColumns();
367
368 /*** Current Enumeration. */
369 private Enumeration currentEnumeration = lockedEnumeration;
370
371 /***
372 * @see java.util.Enumeration#hasMoreElements()
373 */
374 public boolean hasMoreElements() {
375 final boolean hasMore = currentEnumeration.hasMoreElements();
376 if (hasMore) {
377 return hasMore;
378 } else {
379 currentEnumeration = scrollEnumeration;
380 return currentEnumeration.hasMoreElements();
381 }
382 }
383
384 /***
385 * @see java.util.Enumeration#nextElement()
386 */
387 public Object nextElement() {
388 try {
389 return currentEnumeration.nextElement();
390 } catch (NoSuchElementException e) {
391 currentEnumeration = scrollEnumeration;
392 return currentEnumeration.nextElement();
393 }
394 }
395 }
396 }