TableColumn.java 19.7 KB
Newer Older
Tom Tromey committed
1
/* TableColumn.java --
2
   Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
Tom Tromey committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */


package javax.swing.table;

41 42
import java.awt.Component;
import java.awt.Dimension;
Tom Tromey committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;

import javax.swing.event.SwingPropertyChangeSupport;

/**
 * Represents the attributes of a column in a table, including the column index,
 * width, minimum width, preferred width and maximum width.
 * 
 * @author	Andrew Selkirk
 */
public class TableColumn
  implements Serializable
{
  static final long serialVersionUID = -6113660025878112608L;

  /**
61 62 63
   * The name for the <code>columnWidth</code> property (this field is
   * obsolete and no longer used).  Note also that the typo in the value 
   * string is deliberate, to match the specification.
Tom Tromey committed
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
   */
  public static final String COLUMN_WIDTH_PROPERTY = "columWidth";

  /**
   * The name for the <code>headerValue</code> property.
   */
  public static final String HEADER_VALUE_PROPERTY = "headerValue";

  /**
   * The name for the <code>headerRenderer</code> property.
   */
  public static final String HEADER_RENDERER_PROPERTY = "headerRenderer";

  /**
   * The name for the <code>cellRenderer</code> property.
   */
  public static final String CELL_RENDERER_PROPERTY = "cellRenderer";

  /**
   * The index of the corresponding column in the table model.
   */
  protected int modelIndex;

  /**
   * The identifier for the column.
   */
  protected Object identifier;

  /**
93
   * The current width for the column.
Tom Tromey committed
94 95 96 97
   */
  protected int width;

  /**
98
   * The minimum width for the column.
Tom Tromey committed
99 100 101 102
   */
  protected int minWidth = 15;

  /**
103
   * The preferred width for the column.
Tom Tromey committed
104 105 106 107
   */
  private int preferredWidth;

  /**
108
   * The maximum width for the column.
Tom Tromey committed
109 110 111 112
   */
  protected int maxWidth = Integer.MAX_VALUE;

  /**
113
   * The renderer for the column header.
Tom Tromey committed
114 115 116 117
   */
  protected TableCellRenderer headerRenderer;

  /**
118
   * The value for the column header.
Tom Tromey committed
119 120 121 122
   */
  protected Object headerValue;

  /**
123
   * The renderer for the regular cells in this column.
Tom Tromey committed
124 125 126 127
   */
  protected TableCellRenderer cellRenderer;

  /**
128
   * An editor for the regular cells in this column.
Tom Tromey committed
129 130 131 132
   */
  protected TableCellEditor cellEditor;

  /**
133 134
   * A flag that determines whether or not the column is resizable (the default
   * is <code>true</code>).
Tom Tromey committed
135 136 137 138 139 140 141 142 143 144 145
   */
  protected boolean isResizable = true;

  /**
   * resizedPostingDisableCount
   *
   * @deprecated 1.3
   */
  protected transient int resizedPostingDisableCount;

  /**
146
   * A storage and notification mechanism for property change listeners.
Tom Tromey committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
   */
  private SwingPropertyChangeSupport changeSupport =
    new SwingPropertyChangeSupport(this);

  /**
   * Creates a new <code>TableColumn</code> that maps to column 0 in the
   * related table model.  The default width is <code>75</code> units.
   */
  public TableColumn()
  {
    this(0, 75, null, null);
  }

  /**
   * Creates a new <code>TableColumn</code> that maps to the specified column 
   * in the related table model.  The default width is <code>75</code> units.
   * 
   * @param modelIndex the index of the column in the model
   */
  public TableColumn(int modelIndex)
  {
    this(modelIndex, 75, null, null);
  }

  /**
   * Creates a new <code>TableColumn</code> that maps to the specified column 
   * in the related table model, and has the specified <code>width</code>.
   * 
   * @param modelIndex the index of the column in the model
   * @param width the width
   */
  public TableColumn(int modelIndex, int width)
  {
    this(modelIndex, width, null, null);
  }

  /**
   * Creates a new <code>TableColumn</code> that maps to the specified column 
   * in the related table model, and has the specified <code>width</code>,
   * <code>cellRenderer</code> and <code>cellEditor</code>.
   * 
   * @param modelIndex the index of the column in the model
   * @param width the width
   * @param cellRenderer the cell renderer (<code>null</code> permitted).
   * @param cellEditor the cell editor (<code>null</code> permitted).
   */
  public TableColumn(int modelIndex, int width,
                     TableCellRenderer cellRenderer, TableCellEditor cellEditor)
  {
    this.modelIndex = modelIndex;
    this.width = width;
    this.preferredWidth = width;
    this.cellRenderer = cellRenderer;
    this.cellEditor = cellEditor;
    this.headerValue = null;
    this.identifier = null;
  }

  /**
   * Sets the index of the column in the related {@link TableModel} that this
207 208
   * <code>TableColumn</code> maps to, and sends a {@link PropertyChangeEvent}
   * (with the property name 'modelIndex') to all registered listeners.
Tom Tromey committed
209 210
   * 
   * @param modelIndex the column index in the model.
211 212
   * 
   * @see #getModelIndex()
Tom Tromey committed
213 214 215
   */
  public void setModelIndex(int modelIndex)
  {
216 217 218 219 220 221
    if (this.modelIndex != modelIndex)
      {
        int oldValue = this.modelIndex;
        this.modelIndex = modelIndex;
        changeSupport.firePropertyChange("modelIndex", oldValue, modelIndex);
      }
Tom Tromey committed
222 223 224 225 226 227
  }

  /**
   * Returns the index of the column in the related {@link TableModel} that
   * this <code>TableColumn</code> maps to.
   * 
228 229 230
   * @return the model index.
   * 
   * @see #setModelIndex(int)
Tom Tromey committed
231 232 233 234 235 236 237
   */
  public int getModelIndex()
  {
    return modelIndex;
  }

  /**
238 239 240 241
   * Sets the identifier for the column and sends a {@link PropertyChangeEvent}
   * (with the property name 'identifier') to all registered listeners.
   * 
   * @param identifier the identifier (<code>null</code> permitted).
Tom Tromey committed
242
   * 
243
   * @see #getIdentifier()
Tom Tromey committed
244 245 246
   */
  public void setIdentifier(Object identifier)
  {
247 248 249 250 251 252
    if (this.identifier != identifier)
      {       
        Object oldValue = this.identifier;
        this.identifier = identifier;
        changeSupport.firePropertyChange("identifier", oldValue, identifier);
      }
Tom Tromey committed
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
  }

  /**
   * Returns the identifier for the column, or {@link #getHeaderValue()} if the 
   * identifier is <code>null</code>.
   * 
   * @return The identifier (or {@link #getHeaderValue()} if the identifier is 
   *         <code>null</code>).
   */
  public Object getIdentifier()
  {
    if (identifier == null)
      return getHeaderValue();
    return identifier;
  }

  /**
270 271
   * Sets the header value and sends a {@link PropertyChangeEvent} (with the 
   * property name {@link #HEADER_VALUE_PROPERTY}) to all registered listeners.
Tom Tromey committed
272
   * 
273 274 275
   * @param headerValue the value of the header (<code>null</code> permitted).
   * 
   * @see #getHeaderValue()
Tom Tromey committed
276 277 278 279 280 281 282 283
   */
  public void setHeaderValue(Object headerValue)
  {
    if (this.headerValue == headerValue)
      return;
    
    Object oldValue = this.headerValue;
    this.headerValue = headerValue;
284 285
    changeSupport.firePropertyChange(HEADER_VALUE_PROPERTY, oldValue, 
                                     headerValue);
Tom Tromey committed
286 287 288 289 290
  }

  /**
   * Returns the header value.
   * 
291 292 293
   * @return the value of the header.
   * 
   * @see #getHeaderValue()
Tom Tromey committed
294 295 296 297 298 299 300
   */
  public Object getHeaderValue()
  {
    return headerValue;
  }

  /**
301 302 303 304 305
   * Sets the renderer for the column header and sends a 
   * {@link PropertyChangeEvent} (with the property name 
   * {@link #HEADER_RENDERER_PROPERTY}) to all registered listeners.
   * 
   * @param renderer the header renderer (<code>null</code> permitted).
Tom Tromey committed
306
   * 
307
   * @see #getHeaderRenderer()
Tom Tromey committed
308 309 310 311 312 313 314 315
   */
  public void setHeaderRenderer(TableCellRenderer renderer)
  {
    if (headerRenderer == renderer)
      return;
    
    TableCellRenderer oldRenderer = headerRenderer;
    headerRenderer = renderer;
316 317
    changeSupport.firePropertyChange(HEADER_RENDERER_PROPERTY, oldRenderer, 
                                     headerRenderer);
Tom Tromey committed
318 319 320
  }

  /**
321 322 323 324 325
   * Returns the renderer for the column header.
   * 
   * @return The renderer for the column header (possibly <code>null</code>).
   * 
   * @see #setHeaderRenderer(TableCellRenderer)
Tom Tromey committed
326 327 328 329 330 331 332 333
   */
  public TableCellRenderer getHeaderRenderer()
  {
    return headerRenderer;
  }

  /**
   * Sets the renderer for cells in this column and sends a 
334 335
   * {@link PropertyChangeEvent} (with the property name 
   * {@link #CELL_RENDERER_PROPERTY}) to all registered listeners.
Tom Tromey committed
336 337
   * 
   * @param renderer the cell renderer (<code>null</code> permitted).
338 339
   * 
   * @see #getCellRenderer()
Tom Tromey committed
340 341 342 343 344 345 346 347
   */
  public void setCellRenderer(TableCellRenderer renderer)
  {
    if (cellRenderer == renderer)
      return;
    
    TableCellRenderer oldRenderer = cellRenderer;
    cellRenderer = renderer;
348 349
    changeSupport.firePropertyChange(CELL_RENDERER_PROPERTY, oldRenderer, 
                                     cellRenderer);
Tom Tromey committed
350 351 352 353 354
  }

  /**
   * Returns the renderer for the table cells in this column.
   * 
355 356 357
   * @return The cell renderer (possibly <code>null</code>).
   * 
   * @see #setCellRenderer(TableCellRenderer)
Tom Tromey committed
358 359 360 361 362 363 364
   */
  public TableCellRenderer getCellRenderer()
  {
    return cellRenderer;
  }

  /**
365 366 367 368
   * Sets the cell editor for the column and sends a {@link PropertyChangeEvent}
   * (with the property name 'cellEditor') to all registered listeners.
   * 
   * @param cellEditor the cell editor (<code>null</code> permitted).
Tom Tromey committed
369
   * 
370
   * @see #getCellEditor()
Tom Tromey committed
371 372 373
   */
  public void setCellEditor(TableCellEditor cellEditor)
  {
374 375 376 377 378 379
    if (this.cellEditor != cellEditor)
      {
        TableCellEditor oldValue = this.cellEditor;
        this.cellEditor = cellEditor;
        changeSupport.firePropertyChange("cellEditor", oldValue, cellEditor);
      }
Tom Tromey committed
380 381 382
  }

  /**
383 384 385 386
   * Returns the cell editor for the column (the default value is 
   * <code>null</code>).
   * 
   * @return The cell editor (possibly <code>null</code>).
Tom Tromey committed
387
   * 
388
   * @see #setCellEditor(TableCellEditor)
Tom Tromey committed
389 390 391 392 393 394 395
   */
  public TableCellEditor getCellEditor()
  {
    return cellEditor;
  }

  /**
396 397 398 399 400 401
   * Sets the width for the column and sends a {@link PropertyChangeEvent} 
   * (with the property name 'width') to all registered listeners.  If the new
   * width falls outside the range getMinWidth() to getMaxWidth() it is 
   * adjusted to the appropriate boundary value.
   * 
   * @param newWidth the width.
Tom Tromey committed
402
   * 
403
   * @see #getWidth()
Tom Tromey committed
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
   */
  public void setWidth(int newWidth)
  {
    int	oldWidth = width;

    if (newWidth < minWidth)
      width = minWidth;
    else if (newWidth > maxWidth)
      width = maxWidth;
    else
      width = newWidth;

    if (width == oldWidth)
      return;

419 420 421 422
    // We do have a constant field COLUMN_WIDTH_PROPERTY,
    // however, tests show that the actual fired property name is 'width'
    // and even Sun's API docs say that this constant field is obsolete and
    // not used.
423
    changeSupport.firePropertyChange("width", oldWidth, width);
Tom Tromey committed
424 425 426
  }

  /**
427
   * Returns the width for the column (the default value is <code>75</code>).
Tom Tromey committed
428
   * 
429 430 431
   * @return The width.
   *
   * @see #setWidth(int)
Tom Tromey committed
432 433 434 435 436 437 438
   */
  public int getWidth()
  {
    return width;
  }

  /**
439 440 441 442 443 444 445
   * Sets the preferred width for the column and sends a 
   * {@link PropertyChangeEvent} (with the property name 'preferredWidth') to 
   * all registered listeners.  If necessary, the supplied value will be 
   * adjusted to fit in the range {@link #getMinWidth()} to 
   * {@link #getMaxWidth()}.
   * 
   * @param preferredWidth  the preferred width.
Tom Tromey committed
446
   * 
447
   * @see #getPreferredWidth()
Tom Tromey committed
448 449 450
   */
  public void setPreferredWidth(int preferredWidth)
  {
451 452
    int oldPrefWidth = this.preferredWidth;

Tom Tromey committed
453 454 455 456 457 458
    if (preferredWidth < minWidth)
      this.preferredWidth = minWidth;
    else if (preferredWidth > maxWidth)
      this.preferredWidth = maxWidth;
    else
      this.preferredWidth = preferredWidth;
459

460 461
    changeSupport.firePropertyChange("preferredWidth", oldPrefWidth, 
                                     this.preferredWidth);
Tom Tromey committed
462 463 464
  }

  /**
465 466 467 468
   * Returns the preferred width for the column (the default value is 
   * <code>75</code>).
   * 
   * @return The preferred width.
Tom Tromey committed
469
   * 
470
   * @see #setPreferredWidth(int)
Tom Tromey committed
471 472 473 474 475 476 477
   */
  public int getPreferredWidth()
  {
    return preferredWidth;
  }

  /**
478 479 480 481 482
   * Sets the minimum width for the column and sends a 
   * {@link PropertyChangeEvent} (with the property name 'minWidth') to all
   * registered listeners.  If the current <code>width</code> and/or 
   * <code>preferredWidth</code> are less than the new minimum width, they are
   * adjusted accordingly.
Tom Tromey committed
483
   * 
484 485 486
   * @param minWidth  the minimum width (negative values are treated as 0).
   * 
   * @see #getMinWidth()
Tom Tromey committed
487 488 489
   */
  public void setMinWidth(int minWidth)
  {
490 491 492 493 494 495 496 497 498 499 500 501
    if (minWidth < 0)
      minWidth = 0;
    if (this.minWidth != minWidth)
      {
        if (width < minWidth)
          setWidth(minWidth);
        if (preferredWidth < minWidth)
          setPreferredWidth(minWidth);
        int oldValue = this.minWidth;
        this.minWidth = minWidth;
        changeSupport.firePropertyChange("minWidth", oldValue, minWidth);
      }
Tom Tromey committed
502 503 504
  }

  /**
505 506
   * Returns the <code>TableColumn</code>'s minimum width (the default value
   * is <code>15</code>).
Tom Tromey committed
507 508
   * 
   * @return The minimum width.
509 510
   * 
   * @see #setMinWidth(int)
Tom Tromey committed
511 512 513 514 515 516 517
   */
  public int getMinWidth()
  {
    return minWidth;
  }

  /**
518 519 520 521 522 523 524
   * Sets the maximum width for the column and sends a 
   * {@link PropertyChangeEvent} (with the property name 'maxWidth') to all
   * registered listeners.  If the current <code>width</code> and/or 
   * <code>preferredWidth</code> are greater than the new maximum width, they 
   * are adjusted accordingly.
   * 
   * @param maxWidth the maximum width.
Tom Tromey committed
525
   * 
526
   * @see #getMaxWidth()
Tom Tromey committed
527 528 529
   */
  public void setMaxWidth(int maxWidth)
  {
530 531 532 533 534 535 536 537 538 539
    if (this.maxWidth != maxWidth)
      {
        if (width > maxWidth)
          setWidth(maxWidth);
        if (preferredWidth > maxWidth)
          setPreferredWidth(maxWidth);
        int oldValue = this.maxWidth;
        this.maxWidth = maxWidth;
        changeSupport.firePropertyChange("maxWidth", oldValue, maxWidth);
       }
Tom Tromey committed
540 541 542
  }

  /**
543 544
   * Returns the maximum width for the column (the default value is
   * {@link Integer#MAX_VALUE}).
Tom Tromey committed
545
   * 
546 547 548
   * @return The maximum width for the column.
   * 
   * @see #setMaxWidth(int)
Tom Tromey committed
549 550 551 552 553 554 555
   */
  public int getMaxWidth()
  {
    return maxWidth;
  }

  /**
556 557 558
   * Sets the flag that controls whether or not the column is resizable, and
   * sends a {@link PropertyChangeEvent} (with the property name 'isResizable')
   * to all registered listeners.
Tom Tromey committed
559 560
   * 
   * @param isResizable <code>true</code> if this column is resizable,
561 562 563
   * <code>false</code> otherwise.
   * 
   * @see #getResizable()
Tom Tromey committed
564 565 566
   */
  public void setResizable(boolean isResizable)
  {
567 568 569 570 571 572
    if (this.isResizable != isResizable)
      {
        this.isResizable = isResizable;
        changeSupport.firePropertyChange("isResizable", !this.isResizable, 
            isResizable);
      }
Tom Tromey committed
573 574 575
  }

  /**
576
   * Returns the flag that controls whether or not the column is resizable.
Tom Tromey committed
577 578
   * 
   * @return <code>true</code> if this column is resizable,
579 580 581
   * <code>false</code> otherwise.
   * 
   * @see #setResizable(boolean)
Tom Tromey committed
582 583 584 585 586 587 588
   */
  public boolean getResizable()
  {
    return isResizable;
  }

  /**
589 590 591
   * Sets the minimum, maximum, preferred and current width to match the
   * minimum, maximum and preferred width of the header renderer component.
   * If there is no header renderer component, this method does nothing.
Tom Tromey committed
592 593 594
   */
  public void sizeWidthToFit()
  {
595 596 597 598 599 600 601 602 603 604 605
    if (headerRenderer == null)
      return;
    Component c = headerRenderer.getTableCellRendererComponent(null, 
        getHeaderValue(), false, false, 0, 0);
    Dimension min = c.getMinimumSize();
    Dimension max = c.getMaximumSize();
    Dimension pref = c.getPreferredSize();
    setMinWidth(min.width);
    setMaxWidth(max.width);
    setPreferredWidth(pref.width);
    setWidth(pref.width);
Tom Tromey committed
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
  }

  /**
   * This method is empty, unused and deprecated.
   * @deprecated 1.3
   */
  public void disableResizedPosting()
  {
    // Does nothing
  }

  /**
   * This method is empty, unused and deprecated.
   * @deprecated 1.3
   */
  public void enableResizedPosting()
  {
    // Does nothing
  }

  /**
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
   * Adds a listener so that it receives {@link PropertyChangeEvent} 
   * notifications from this column.  The properties defined by the column are:
   * <ul>
   * <li><code>width</code> - see {@link #setWidth(int)};</li>
   * <li><code>preferredWidth</code> - see {@link #setPreferredWidth(int)};</li>
   * <li><code>minWidth</code> - see {@link #setMinWidth(int)};</li> 
   * <li><code>maxWidth</code> - see {@link #setMaxWidth(int)};</li>
   * <li><code>modelIndex</code> - see {@link #setModelIndex(int)};</li>
   * <li><code>isResizable</code> - see {@link #setResizable(boolean)};</li>
   * <li><code>cellRenderer</code> - see 
   *   {@link #setCellRenderer(TableCellRenderer)};</li>
   * <li><code>cellEditor</code> - see 
   *   {@link #setCellEditor(TableCellEditor)};</li>
   * <li><code>headerRenderer</code> - see 
   *   {@link #setHeaderRenderer(TableCellRenderer)};</li>
   * <li><code>headerValue</code> - see {@link #setHeaderValue(Object)};</li>
   * <li><code>identifier</code> - see {@link #setIdentifier(Object)}.</li>
   * </ul>
   * 
   * @param listener the listener to add (<code>null</code> is ignored).
Tom Tromey committed
647
   * 
648
   * @see #removePropertyChangeListener(PropertyChangeListener)
Tom Tromey committed
649
   */
650 651
  public synchronized void addPropertyChangeListener(
      PropertyChangeListener listener)
Tom Tromey committed
652 653 654 655 656
  {
    changeSupport.addPropertyChangeListener(listener);
  }

  /**
657 658 659 660 661 662
   * Removes a listener so that it no longer receives 
   * {@link PropertyChangeEvent} notifications from this column.  If 
   * <code>listener</code> is not registered with the column, or is 
   * <code>null</code>, this method does nothing.
   * 
   * @param listener the listener to remove (<code>null</code> is ignored).
Tom Tromey committed
663
   */
664 665
  public synchronized void removePropertyChangeListener(
      PropertyChangeListener listener)
Tom Tromey committed
666 667 668 669 670 671
  {
    changeSupport.removePropertyChangeListener(listener);
  }

  /**
   * Returns the property change listeners for this <code>TableColumn</code>.
672 673 674 675
   * An empty array is returned if there are currently no listeners registered.
   * 
   * @return The property change listeners registered with this column.
   * 
Tom Tromey committed
676 677 678 679 680 681 682 683
   * @since 1.4
   */
  public PropertyChangeListener[] getPropertyChangeListeners()
  {
    return changeSupport.getPropertyChangeListeners();
  }

  /**
684 685 686 687
   * Creates and returns a default renderer for the column header (in this case,
   * a new instance of {@link DefaultTableCellRenderer}).
   * 
   * @return A default renderer for the column header.
Tom Tromey committed
688 689 690 691 692 693
   */
  protected TableCellRenderer createDefaultHeaderRenderer()
  {
    return new DefaultTableCellRenderer();
  }
}