View Javadoc

1   /*
2   This file is part of the xframe software package
3   hosted at http://xframe.sourceforge.net
4   
5   Copyright (c) 2003 Kurt Riede.
6   
7   This library is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Lesser General Public
9   License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11  
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16  
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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  //    private JTable getLockedTable() {
69  //        return this.table.getLockedTable();
70  //    }
71  
72      /***
73       * Convinience method to access the scrollable table from the JXTable.
74       *
75       * @return the scrollable table
76       */
77  //    private JTable getScrollTable() {
78  //        return this.table.getScrollTable();
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             // move within locked table
210             lockedColumnModel.moveColumn(columnIndex, newIndex);
211         } else if (columnIndex < getFrozenColumns() && newIndex >= getFrozenColumns()) {
212             // move from locked to scrollable
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             // move from scrollable to locked
219             final TableColumn tableColumn = scrollColumnModel.getColumn(columnIndex);
220             scrollColumnModel.removeColumn(tableColumn);
221             lockedColumnModel.addColumn(tableColumn);
222             lockedColumnModel.moveColumn(lockedColumnModel.getColumnCount(), newIndex);
223         } else {
224             // move within scrollable
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         // TODO Check if the listener must get wrapped to convert column indices
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 // TODO        lockedColumnModel.setPreferredScrollableViewportSize(getLockedTable().getPreferredSize());
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 //      TODO        lockedColumnModel.setPreferredScrollableViewportSize(getLockedTable().getPreferredSize());
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 }