1 /* TableColumn.java --
2    Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.swing.table;
40 
41 import java.awt.Component;
42 import java.awt.Dimension;
43 import java.beans.PropertyChangeEvent;
44 import java.beans.PropertyChangeListener;
45 import java.io.Serializable;
46 
47 import javax.swing.event.SwingPropertyChangeSupport;
48 
49 /**
50  * Represents the attributes of a column in a table, including the column index,
51  * width, minimum width, preferred width and maximum width.
52  *
53  * @author      Andrew Selkirk
54  */
55 public class TableColumn
56   implements Serializable
57 {
58   static final long serialVersionUID = -6113660025878112608L;
59 
60   /**
61    * The name for the <code>columnWidth</code> property (this field is
62    * obsolete and no longer used).  Note also that the typo in the value
63    * string is deliberate, to match the specification.
64    */
65   public static final String COLUMN_WIDTH_PROPERTY = "columWidth";
66 
67   /**
68    * The name for the <code>headerValue</code> property.
69    */
70   public static final String HEADER_VALUE_PROPERTY = "headerValue";
71 
72   /**
73    * The name for the <code>headerRenderer</code> property.
74    */
75   public static final String HEADER_RENDERER_PROPERTY = "headerRenderer";
76 
77   /**
78    * The name for the <code>cellRenderer</code> property.
79    */
80   public static final String CELL_RENDERER_PROPERTY = "cellRenderer";
81 
82   /**
83    * The index of the corresponding column in the table model.
84    */
85   protected int modelIndex;
86 
87   /**
88    * The identifier for the column.
89    */
90   protected Object identifier;
91 
92   /**
93    * The current width for the column.
94    */
95   protected int width;
96 
97   /**
98    * The minimum width for the column.
99    */
100   protected int minWidth = 15;
101 
102   /**
103    * The preferred width for the column.
104    */
105   private int preferredWidth;
106 
107   /**
108    * The maximum width for the column.
109    */
110   protected int maxWidth = Integer.MAX_VALUE;
111 
112   /**
113    * The renderer for the column header.
114    */
115   protected TableCellRenderer headerRenderer;
116 
117   /**
118    * The value for the column header.
119    */
120   protected Object headerValue;
121 
122   /**
123    * The renderer for the regular cells in this column.
124    */
125   protected TableCellRenderer cellRenderer;
126 
127   /**
128    * An editor for the regular cells in this column.
129    */
130   protected TableCellEditor cellEditor;
131 
132   /**
133    * A flag that determines whether or not the column is resizable (the default
134    * is <code>true</code>).
135    */
136   protected boolean isResizable = true;
137 
138   /**
139    * resizedPostingDisableCount
140    *
141    * @deprecated 1.3
142    */
143   protected transient int resizedPostingDisableCount;
144 
145   /**
146    * A storage and notification mechanism for property change listeners.
147    */
148   private SwingPropertyChangeSupport changeSupport =
149     new SwingPropertyChangeSupport(this);
150 
151   /**
152    * Creates a new <code>TableColumn</code> that maps to column 0 in the
153    * related table model.  The default width is <code>75</code> units.
154    */
TableColumn()155   public TableColumn()
156   {
157     this(0, 75, null, null);
158   }
159 
160   /**
161    * Creates a new <code>TableColumn</code> that maps to the specified column
162    * in the related table model.  The default width is <code>75</code> units.
163    *
164    * @param modelIndex the index of the column in the model
165    */
TableColumn(int modelIndex)166   public TableColumn(int modelIndex)
167   {
168     this(modelIndex, 75, null, null);
169   }
170 
171   /**
172    * Creates a new <code>TableColumn</code> that maps to the specified column
173    * in the related table model, and has the specified <code>width</code>.
174    *
175    * @param modelIndex the index of the column in the model
176    * @param width the width
177    */
TableColumn(int modelIndex, int width)178   public TableColumn(int modelIndex, int width)
179   {
180     this(modelIndex, width, null, null);
181   }
182 
183   /**
184    * Creates a new <code>TableColumn</code> that maps to the specified column
185    * in the related table model, and has the specified <code>width</code>,
186    * <code>cellRenderer</code> and <code>cellEditor</code>.
187    *
188    * @param modelIndex the index of the column in the model
189    * @param width the width
190    * @param cellRenderer the cell renderer (<code>null</code> permitted).
191    * @param cellEditor the cell editor (<code>null</code> permitted).
192    */
TableColumn(int modelIndex, int width, TableCellRenderer cellRenderer, TableCellEditor cellEditor)193   public TableColumn(int modelIndex, int width,
194                      TableCellRenderer cellRenderer, TableCellEditor cellEditor)
195   {
196     this.modelIndex = modelIndex;
197     this.width = width;
198     this.preferredWidth = width;
199     this.cellRenderer = cellRenderer;
200     this.cellEditor = cellEditor;
201     this.headerValue = null;
202     this.identifier = null;
203   }
204 
205   /**
206    * Sets the index of the column in the related {@link TableModel} that this
207    * <code>TableColumn</code> maps to, and sends a {@link PropertyChangeEvent}
208    * (with the property name 'modelIndex') to all registered listeners.
209    *
210    * @param modelIndex the column index in the model.
211    *
212    * @see #getModelIndex()
213    */
setModelIndex(int modelIndex)214   public void setModelIndex(int modelIndex)
215   {
216     if (this.modelIndex != modelIndex)
217       {
218         int oldValue = this.modelIndex;
219         this.modelIndex = modelIndex;
220         changeSupport.firePropertyChange("modelIndex", oldValue, modelIndex);
221       }
222   }
223 
224   /**
225    * Returns the index of the column in the related {@link TableModel} that
226    * this <code>TableColumn</code> maps to.
227    *
228    * @return the model index.
229    *
230    * @see #setModelIndex(int)
231    */
getModelIndex()232   public int getModelIndex()
233   {
234     return modelIndex;
235   }
236 
237   /**
238    * Sets the identifier for the column and sends a {@link PropertyChangeEvent}
239    * (with the property name 'identifier') to all registered listeners.
240    *
241    * @param identifier the identifier (<code>null</code> permitted).
242    *
243    * @see #getIdentifier()
244    */
setIdentifier(Object identifier)245   public void setIdentifier(Object identifier)
246   {
247     if (this.identifier != identifier)
248       {
249         Object oldValue = this.identifier;
250         this.identifier = identifier;
251         changeSupport.firePropertyChange("identifier", oldValue, identifier);
252       }
253   }
254 
255   /**
256    * Returns the identifier for the column, or {@link #getHeaderValue()} if the
257    * identifier is <code>null</code>.
258    *
259    * @return The identifier (or {@link #getHeaderValue()} if the identifier is
260    *         <code>null</code>).
261    */
getIdentifier()262   public Object getIdentifier()
263   {
264     if (identifier == null)
265       return getHeaderValue();
266     return identifier;
267   }
268 
269   /**
270    * Sets the header value and sends a {@link PropertyChangeEvent} (with the
271    * property name {@link #HEADER_VALUE_PROPERTY}) to all registered listeners.
272    *
273    * @param headerValue the value of the header (<code>null</code> permitted).
274    *
275    * @see #getHeaderValue()
276    */
setHeaderValue(Object headerValue)277   public void setHeaderValue(Object headerValue)
278   {
279     if (this.headerValue == headerValue)
280       return;
281 
282     Object oldValue = this.headerValue;
283     this.headerValue = headerValue;
284     changeSupport.firePropertyChange(HEADER_VALUE_PROPERTY, oldValue,
285                                      headerValue);
286   }
287 
288   /**
289    * Returns the header value.
290    *
291    * @return the value of the header.
292    *
293    * @see #getHeaderValue()
294    */
getHeaderValue()295   public Object getHeaderValue()
296   {
297     return headerValue;
298   }
299 
300   /**
301    * Sets the renderer for the column header and sends a
302    * {@link PropertyChangeEvent} (with the property name
303    * {@link #HEADER_RENDERER_PROPERTY}) to all registered listeners.
304    *
305    * @param renderer the header renderer (<code>null</code> permitted).
306    *
307    * @see #getHeaderRenderer()
308    */
setHeaderRenderer(TableCellRenderer renderer)309   public void setHeaderRenderer(TableCellRenderer renderer)
310   {
311     if (headerRenderer == renderer)
312       return;
313 
314     TableCellRenderer oldRenderer = headerRenderer;
315     headerRenderer = renderer;
316     changeSupport.firePropertyChange(HEADER_RENDERER_PROPERTY, oldRenderer,
317                                      headerRenderer);
318   }
319 
320   /**
321    * Returns the renderer for the column header.
322    *
323    * @return The renderer for the column header (possibly <code>null</code>).
324    *
325    * @see #setHeaderRenderer(TableCellRenderer)
326    */
getHeaderRenderer()327   public TableCellRenderer getHeaderRenderer()
328   {
329     return headerRenderer;
330   }
331 
332   /**
333    * Sets the renderer for cells in this column and sends a
334    * {@link PropertyChangeEvent} (with the property name
335    * {@link #CELL_RENDERER_PROPERTY}) to all registered listeners.
336    *
337    * @param renderer the cell renderer (<code>null</code> permitted).
338    *
339    * @see #getCellRenderer()
340    */
setCellRenderer(TableCellRenderer renderer)341   public void setCellRenderer(TableCellRenderer renderer)
342   {
343     if (cellRenderer == renderer)
344       return;
345 
346     TableCellRenderer oldRenderer = cellRenderer;
347     cellRenderer = renderer;
348     changeSupport.firePropertyChange(CELL_RENDERER_PROPERTY, oldRenderer,
349                                      cellRenderer);
350   }
351 
352   /**
353    * Returns the renderer for the table cells in this column.
354    *
355    * @return The cell renderer (possibly <code>null</code>).
356    *
357    * @see #setCellRenderer(TableCellRenderer)
358    */
getCellRenderer()359   public TableCellRenderer getCellRenderer()
360   {
361     return cellRenderer;
362   }
363 
364   /**
365    * Sets the cell editor for the column and sends a {@link PropertyChangeEvent}
366    * (with the property name 'cellEditor') to all registered listeners.
367    *
368    * @param cellEditor the cell editor (<code>null</code> permitted).
369    *
370    * @see #getCellEditor()
371    */
setCellEditor(TableCellEditor cellEditor)372   public void setCellEditor(TableCellEditor cellEditor)
373   {
374     if (this.cellEditor != cellEditor)
375       {
376         TableCellEditor oldValue = this.cellEditor;
377         this.cellEditor = cellEditor;
378         changeSupport.firePropertyChange("cellEditor", oldValue, cellEditor);
379       }
380   }
381 
382   /**
383    * Returns the cell editor for the column (the default value is
384    * <code>null</code>).
385    *
386    * @return The cell editor (possibly <code>null</code>).
387    *
388    * @see #setCellEditor(TableCellEditor)
389    */
getCellEditor()390   public TableCellEditor getCellEditor()
391   {
392     return cellEditor;
393   }
394 
395   /**
396    * Sets the width for the column and sends a {@link PropertyChangeEvent}
397    * (with the property name 'width') to all registered listeners.  If the new
398    * width falls outside the range getMinWidth() to getMaxWidth() it is
399    * adjusted to the appropriate boundary value.
400    *
401    * @param newWidth the width.
402    *
403    * @see #getWidth()
404    */
setWidth(int newWidth)405   public void setWidth(int newWidth)
406   {
407     int oldWidth = width;
408 
409     if (newWidth < minWidth)
410       width = minWidth;
411     else if (newWidth > maxWidth)
412       width = maxWidth;
413     else
414       width = newWidth;
415 
416     if (width == oldWidth)
417       return;
418 
419     // We do have a constant field COLUMN_WIDTH_PROPERTY,
420     // however, tests show that the actual fired property name is 'width'
421     // and even Sun's API docs say that this constant field is obsolete and
422     // not used.
423     changeSupport.firePropertyChange("width", oldWidth, width);
424   }
425 
426   /**
427    * Returns the width for the column (the default value is <code>75</code>).
428    *
429    * @return The width.
430    *
431    * @see #setWidth(int)
432    */
getWidth()433   public int getWidth()
434   {
435     return width;
436   }
437 
438   /**
439    * Sets the preferred width for the column and sends a
440    * {@link PropertyChangeEvent} (with the property name 'preferredWidth') to
441    * all registered listeners.  If necessary, the supplied value will be
442    * adjusted to fit in the range {@link #getMinWidth()} to
443    * {@link #getMaxWidth()}.
444    *
445    * @param preferredWidth  the preferred width.
446    *
447    * @see #getPreferredWidth()
448    */
setPreferredWidth(int preferredWidth)449   public void setPreferredWidth(int preferredWidth)
450   {
451     int oldPrefWidth = this.preferredWidth;
452 
453     if (preferredWidth < minWidth)
454       this.preferredWidth = minWidth;
455     else if (preferredWidth > maxWidth)
456       this.preferredWidth = maxWidth;
457     else
458       this.preferredWidth = preferredWidth;
459 
460     changeSupport.firePropertyChange("preferredWidth", oldPrefWidth,
461                                      this.preferredWidth);
462   }
463 
464   /**
465    * Returns the preferred width for the column (the default value is
466    * <code>75</code>).
467    *
468    * @return The preferred width.
469    *
470    * @see #setPreferredWidth(int)
471    */
getPreferredWidth()472   public int getPreferredWidth()
473   {
474     return preferredWidth;
475   }
476 
477   /**
478    * Sets the minimum width for the column and sends a
479    * {@link PropertyChangeEvent} (with the property name 'minWidth') to all
480    * registered listeners.  If the current <code>width</code> and/or
481    * <code>preferredWidth</code> are less than the new minimum width, they are
482    * adjusted accordingly.
483    *
484    * @param minWidth  the minimum width (negative values are treated as 0).
485    *
486    * @see #getMinWidth()
487    */
setMinWidth(int minWidth)488   public void setMinWidth(int minWidth)
489   {
490     if (minWidth < 0)
491       minWidth = 0;
492     if (this.minWidth != minWidth)
493       {
494         if (width < minWidth)
495           setWidth(minWidth);
496         if (preferredWidth < minWidth)
497           setPreferredWidth(minWidth);
498         int oldValue = this.minWidth;
499         this.minWidth = minWidth;
500         changeSupport.firePropertyChange("minWidth", oldValue, minWidth);
501       }
502   }
503 
504   /**
505    * Returns the <code>TableColumn</code>'s minimum width (the default value
506    * is <code>15</code>).
507    *
508    * @return The minimum width.
509    *
510    * @see #setMinWidth(int)
511    */
getMinWidth()512   public int getMinWidth()
513   {
514     return minWidth;
515   }
516 
517   /**
518    * Sets the maximum width for the column and sends a
519    * {@link PropertyChangeEvent} (with the property name 'maxWidth') to all
520    * registered listeners.  If the current <code>width</code> and/or
521    * <code>preferredWidth</code> are greater than the new maximum width, they
522    * are adjusted accordingly.
523    *
524    * @param maxWidth the maximum width.
525    *
526    * @see #getMaxWidth()
527    */
setMaxWidth(int maxWidth)528   public void setMaxWidth(int maxWidth)
529   {
530     if (this.maxWidth != maxWidth)
531       {
532         if (width > maxWidth)
533           setWidth(maxWidth);
534         if (preferredWidth > maxWidth)
535           setPreferredWidth(maxWidth);
536         int oldValue = this.maxWidth;
537         this.maxWidth = maxWidth;
538         changeSupport.firePropertyChange("maxWidth", oldValue, maxWidth);
539        }
540   }
541 
542   /**
543    * Returns the maximum width for the column (the default value is
544    * {@link Integer#MAX_VALUE}).
545    *
546    * @return The maximum width for the column.
547    *
548    * @see #setMaxWidth(int)
549    */
getMaxWidth()550   public int getMaxWidth()
551   {
552     return maxWidth;
553   }
554 
555   /**
556    * Sets the flag that controls whether or not the column is resizable, and
557    * sends a {@link PropertyChangeEvent} (with the property name 'isResizable')
558    * to all registered listeners.
559    *
560    * @param isResizable <code>true</code> if this column is resizable,
561    * <code>false</code> otherwise.
562    *
563    * @see #getResizable()
564    */
setResizable(boolean isResizable)565   public void setResizable(boolean isResizable)
566   {
567     if (this.isResizable != isResizable)
568       {
569         this.isResizable = isResizable;
570         changeSupport.firePropertyChange("isResizable", !this.isResizable,
571             isResizable);
572       }
573   }
574 
575   /**
576    * Returns the flag that controls whether or not the column is resizable.
577    *
578    * @return <code>true</code> if this column is resizable,
579    * <code>false</code> otherwise.
580    *
581    * @see #setResizable(boolean)
582    */
getResizable()583   public boolean getResizable()
584   {
585     return isResizable;
586   }
587 
588   /**
589    * Sets the minimum, maximum, preferred and current width to match the
590    * minimum, maximum and preferred width of the header renderer component.
591    * If there is no header renderer component, this method does nothing.
592    */
sizeWidthToFit()593   public void sizeWidthToFit()
594   {
595     if (headerRenderer == null)
596       return;
597     Component c = headerRenderer.getTableCellRendererComponent(null,
598         getHeaderValue(), false, false, 0, 0);
599     Dimension min = c.getMinimumSize();
600     Dimension max = c.getMaximumSize();
601     Dimension pref = c.getPreferredSize();
602     setMinWidth(min.width);
603     setMaxWidth(max.width);
604     setPreferredWidth(pref.width);
605     setWidth(pref.width);
606   }
607 
608   /**
609    * This method is empty, unused and deprecated.
610    * @deprecated 1.3
611    */
disableResizedPosting()612   public void disableResizedPosting()
613   {
614     // Does nothing
615   }
616 
617   /**
618    * This method is empty, unused and deprecated.
619    * @deprecated 1.3
620    */
enableResizedPosting()621   public void enableResizedPosting()
622   {
623     // Does nothing
624   }
625 
626   /**
627    * Adds a listener so that it receives {@link PropertyChangeEvent}
628    * notifications from this column.  The properties defined by the column are:
629    * <ul>
630    * <li><code>width</code> - see {@link #setWidth(int)};</li>
631    * <li><code>preferredWidth</code> - see {@link #setPreferredWidth(int)};</li>
632    * <li><code>minWidth</code> - see {@link #setMinWidth(int)};</li>
633    * <li><code>maxWidth</code> - see {@link #setMaxWidth(int)};</li>
634    * <li><code>modelIndex</code> - see {@link #setModelIndex(int)};</li>
635    * <li><code>isResizable</code> - see {@link #setResizable(boolean)};</li>
636    * <li><code>cellRenderer</code> - see
637    *   {@link #setCellRenderer(TableCellRenderer)};</li>
638    * <li><code>cellEditor</code> - see
639    *   {@link #setCellEditor(TableCellEditor)};</li>
640    * <li><code>headerRenderer</code> - see
641    *   {@link #setHeaderRenderer(TableCellRenderer)};</li>
642    * <li><code>headerValue</code> - see {@link #setHeaderValue(Object)};</li>
643    * <li><code>identifier</code> - see {@link #setIdentifier(Object)}.</li>
644    * </ul>
645    *
646    * @param listener the listener to add (<code>null</code> is ignored).
647    *
648    * @see #removePropertyChangeListener(PropertyChangeListener)
649    */
addPropertyChangeListener( PropertyChangeListener listener)650   public synchronized void addPropertyChangeListener(
651       PropertyChangeListener listener)
652   {
653     changeSupport.addPropertyChangeListener(listener);
654   }
655 
656   /**
657    * Removes a listener so that it no longer receives
658    * {@link PropertyChangeEvent} notifications from this column.  If
659    * <code>listener</code> is not registered with the column, or is
660    * <code>null</code>, this method does nothing.
661    *
662    * @param listener the listener to remove (<code>null</code> is ignored).
663    */
removePropertyChangeListener( PropertyChangeListener listener)664   public synchronized void removePropertyChangeListener(
665       PropertyChangeListener listener)
666   {
667     changeSupport.removePropertyChangeListener(listener);
668   }
669 
670   /**
671    * Returns the property change listeners for this <code>TableColumn</code>.
672    * An empty array is returned if there are currently no listeners registered.
673    *
674    * @return The property change listeners registered with this column.
675    *
676    * @since 1.4
677    */
getPropertyChangeListeners()678   public PropertyChangeListener[] getPropertyChangeListeners()
679   {
680     return changeSupport.getPropertyChangeListeners();
681   }
682 
683   /**
684    * Creates and returns a default renderer for the column header (in this case,
685    * a new instance of {@link DefaultTableCellRenderer}).
686    *
687    * @return A default renderer for the column header.
688    */
createDefaultHeaderRenderer()689   protected TableCellRenderer createDefaultHeaderRenderer()
690   {
691     return new DefaultTableCellRenderer();
692   }
693 }
694