001 /* TableColumn.java --
002 Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.swing.table;
040
041 import java.awt.Component;
042 import java.awt.Dimension;
043 import java.beans.PropertyChangeEvent;
044 import java.beans.PropertyChangeListener;
045 import java.io.Serializable;
046
047 import javax.swing.event.SwingPropertyChangeSupport;
048
049 /**
050 * Represents the attributes of a column in a table, including the column index,
051 * width, minimum width, preferred width and maximum width.
052 *
053 * @author Andrew Selkirk
054 */
055 public class TableColumn
056 implements Serializable
057 {
058 static final long serialVersionUID = -6113660025878112608L;
059
060 /**
061 * The name for the <code>columnWidth</code> property (this field is
062 * obsolete and no longer used). Note also that the typo in the value
063 * string is deliberate, to match the specification.
064 */
065 public static final String COLUMN_WIDTH_PROPERTY = "columWidth";
066
067 /**
068 * The name for the <code>headerValue</code> property.
069 */
070 public static final String HEADER_VALUE_PROPERTY = "headerValue";
071
072 /**
073 * The name for the <code>headerRenderer</code> property.
074 */
075 public static final String HEADER_RENDERER_PROPERTY = "headerRenderer";
076
077 /**
078 * The name for the <code>cellRenderer</code> property.
079 */
080 public static final String CELL_RENDERER_PROPERTY = "cellRenderer";
081
082 /**
083 * The index of the corresponding column in the table model.
084 */
085 protected int modelIndex;
086
087 /**
088 * The identifier for the column.
089 */
090 protected Object identifier;
091
092 /**
093 * The current width for the column.
094 */
095 protected int width;
096
097 /**
098 * The minimum width for the column.
099 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
612 public void disableResizedPosting()
613 {
614 // Does nothing
615 }
616
617 /**
618 * This method is empty, unused and deprecated.
619 * @deprecated 1.3
620 */
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 */
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 */
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 */
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 */
689 protected TableCellRenderer createDefaultHeaderRenderer()
690 {
691 return new DefaultTableCellRenderer();
692 }
693 }