001: /*
002: * This file is part of the Echo Web Application Framework (hereinafter "Echo").
003: * Copyright (C) 2002-2005 NextApp, Inc.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package nextapp.echo2.app;
031:
032: import java.util.EventListener;
033: import java.util.HashMap;
034: import java.util.Map;
035:
036: import nextapp.echo2.app.event.ActionEvent;
037: import nextapp.echo2.app.event.ActionListener;
038: import nextapp.echo2.app.event.ChangeEvent;
039: import nextapp.echo2.app.event.ChangeListener;
040: import nextapp.echo2.app.event.TableColumnModelEvent;
041: import nextapp.echo2.app.event.TableColumnModelListener;
042: import nextapp.echo2.app.event.TableModelEvent;
043: import nextapp.echo2.app.event.TableModelListener;
044: import nextapp.echo2.app.list.DefaultListSelectionModel;
045: import nextapp.echo2.app.list.ListSelectionModel;
046: import nextapp.echo2.app.table.DefaultTableCellRenderer;
047: import nextapp.echo2.app.table.DefaultTableColumnModel;
048: import nextapp.echo2.app.table.DefaultTableModel;
049: import nextapp.echo2.app.table.TableCellRenderer;
050: import nextapp.echo2.app.table.TableColumn;
051: import nextapp.echo2.app.table.TableColumnModel;
052: import nextapp.echo2.app.table.TableModel;
053:
054: /**
055: * A component used to display data in a tabular format.
056: *
057: * @see nextapp.echo2.app.table
058: */
059: public class Table extends Component {
060:
061: /**
062: * The default renderer for table cells.
063: */
064: public static final TableCellRenderer DEFAULT_TABLE_CELL_RENDERER = new DefaultTableCellRenderer();
065:
066: public static final String PROPERTY_ACTION_COMMAND = "actionCommand";
067: public static final String PROPERTY_BORDER = "border";
068: public static final String PROPERTY_INSETS = "insets";
069: public static final String PROPERTY_ROLLOVER_BACKGROUND = "rolloverBackground";
070: public static final String PROPERTY_ROLLOVER_BACKGROUND_IMAGE = "rolloverBackgroundImage";
071: public static final String PROPERTY_ROLLOVER_ENABLED = "rolloverEnabled";
072: public static final String PROPERTY_ROLLOVER_FONT = "rolloverFont";
073: public static final String PROPERTY_ROLLOVER_FOREGROUND = "rolloverForeground";
074: public static final String PROPERTY_SELECTION_BACKGROUND = "selectionBackground";
075: public static final String PROPERTY_SELECTION_BACKGROUND_IMAGE = "selectionBackgroundImage";
076: public static final String PROPERTY_SELECTION_ENABLED = "selectionEnabled";
077: public static final String PROPERTY_SELECTION_FONT = "selectionFont";
078: public static final String PROPERTY_SELECTION_FOREGROUND = "selectionForeground";
079: public static final String PROPERTY_WIDTH = "width";
080:
081: public static final String INPUT_ACTION = "action";
082:
083: public static final String ACTION_LISTENERS_CHANGED_PROPERTY = "actionListeners";
084: public static final String AUTO_CREATE_COLUMNS_FROM_MODEL_CHANGED_PROPERTY = "autoCreateColumnsFromModel";
085: public static final String COLUMN_MODEL_CHANGED_PROPERTY = "columnModel";
086: public static final String DEFAULT_HEADER_RENDERER_CHANGED_PROPERTY = "defaultHeaderRenderer";
087: public static final String DEFAULT_RENDERER_CHANGED_PROPERTY = "defaultRenderer";
088: public static final String HEADER_VISIBLE_CHANGED_PROPERTY = "headerVisible";
089: public static final String MODEL_CHANGED_PROPERTY = "model";
090: public static final String SELECTION_CHANGED_PROPERTY = "selection";
091: public static final String SELECTION_MODEL_CHANGED_PROPERTY = "selectionModel";
092:
093: public static final int HEADER_ROW = -1;
094:
095: private boolean autoCreateColumnsFromModel;
096: private boolean headerVisible = true;
097: private TableModel model;
098: private TableColumnModel columnModel;
099: private boolean valid;
100: private Map defaultRendererMap = new HashMap();
101: private TableCellRenderer defaultHeaderRenderer;
102: private ListSelectionModel selectionModel;
103: private boolean suppressChangeNotifications;
104:
105: /**
106: * Listener to monitor changes to model.
107: */
108: private TableModelListener modelListener = new TableModelListener() {
109:
110: /**
111: * @see nextapp.echo2.app.event.TableModelListener#tableChanged(nextapp.echo2.app.event.TableModelEvent)
112: */
113: public void tableChanged(TableModelEvent e) {
114: invalidate();
115: if ((e == null || e.getType() == TableModelEvent.STRUCTURE_CHANGED)
116: && isAutoCreateColumnsFromModel()) {
117: createDefaultColumnsFromModel();
118: }
119: }
120: };
121:
122: /**
123: * Listener to monitor changes to column model.
124: */
125: private TableColumnModelListener columnModelListener = new TableColumnModelListener() {
126:
127: /**
128: * @see nextapp.echo2.app.event.TableColumnModelListener#columnAdded(nextapp.echo2.app.event.TableColumnModelEvent)
129: */
130: public void columnAdded(TableColumnModelEvent e) {
131: invalidate();
132: }
133:
134: /**
135: * @see nextapp.echo2.app.event.TableColumnModelListener#columnMoved(nextapp.echo2.app.event.TableColumnModelEvent)
136: */
137: public void columnMoved(TableColumnModelEvent e) {
138: invalidate();
139: }
140:
141: /**
142: * @see nextapp.echo2.app.event.TableColumnModelListener#columnRemoved(nextapp.echo2.app.event.TableColumnModelEvent)
143: */
144: public void columnRemoved(TableColumnModelEvent e) {
145: invalidate();
146: }
147: };
148:
149: /**
150: * Local handler for list selection events.
151: */
152: private ChangeListener changeHandler = new ChangeListener() {
153:
154: /**
155: * @see nextapp.echo2.app.event.ChangeListener#stateChanged(nextapp.echo2.app.event.ChangeEvent)
156: */
157: public void stateChanged(ChangeEvent e) {
158: if (!suppressChangeNotifications) {
159: firePropertyChange(SELECTION_CHANGED_PROPERTY, null,
160: null);
161: }
162: }
163: };
164:
165: /**
166: * Creates a new <code>Table</code> with an empty
167: * <code>DefaultTableModel</code>.
168: */
169: public Table() {
170: this (new DefaultTableModel());
171: }
172:
173: /**
174: * Creates a new <code>Table</code> with a new
175: * <code>DefaultTableModel</code> with the specified dimensions.
176: *
177: * @param columns the initial column count
178: * @param rows the initial row count
179: */
180: public Table(int columns, int rows) {
181: this (new DefaultTableModel(columns, rows));
182: }
183:
184: /**
185: * Creates a <code>Table</code> using the supplied
186: * <code>TableModel</code>.
187: *
188: * @param model the initial model
189: */
190: public Table(TableModel model) {
191: this (model, null);
192: }
193:
194: /**
195: * Creates a <code>Table</code> with the supplied
196: * <code>TableModel</code> and the specified <code>TableColumnModel</code>.
197: *
198: * @param model the initial model
199: * @param columnModel the initial column model
200: */
201: public Table(TableModel model, TableColumnModel columnModel) {
202: super ();
203:
204: if (columnModel == null) {
205: setColumnModel(new DefaultTableColumnModel());
206: setAutoCreateColumnsFromModel(true);
207: } else {
208: setColumnModel(columnModel);
209: }
210: setSelectionModel(new DefaultListSelectionModel());
211: setModel(model);
212: }
213:
214: /**
215: * Returns the action command which will be provided in
216: * <code>ActionEvent</code>s fired by this
217: * <code>Table</code>.
218: *
219: * @return the action command
220: */
221: public String getActionCommand() {
222: return (String) getProperty(PROPERTY_ACTION_COMMAND);
223: }
224:
225: /**
226: * Adds an <code>ActionListener</code> to the <code>Table</code>.
227: * <code>ActionListener</code>s will be invoked when the user
228: * selects a row.
229: *
230: * @param l the <code>ActionListener</code> to add
231: */
232: public void addActionListener(ActionListener l) {
233: getEventListenerList().addListener(ActionListener.class, l);
234: // Notification of action listener changes is provided due to
235: // existence of hasActionListeners() method.
236: firePropertyChange(ACTION_LISTENERS_CHANGED_PROPERTY, null, l);
237: }
238:
239: /**
240: * Creates a <code>TableColumnModel</code> based on the
241: * <code>TableModel</code>. This method is invoked automatically when the
242: * <code>TableModel</code>'s structure changes if the
243: * <code>autoCreateColumnsFromModel</code> flag is set.
244: */
245: public void createDefaultColumnsFromModel() {
246: if (model != null) {
247: while (columnModel.getColumnCount() > 0) {
248: columnModel.removeColumn(columnModel.getColumn(0));
249: }
250:
251: int columnCount = model.getColumnCount();
252: for (int index = 0; index < columnCount; ++index) {
253: columnModel.addColumn(new TableColumn(index));
254: }
255: }
256: }
257:
258: /**
259: * Re-renders changed rows.
260: */
261: protected void doRender() {
262: removeAll();
263: int rowCount = model.getRowCount();
264: int columnCount = columnModel.getColumnCount();
265:
266: TableColumn[] tableColumns = new TableColumn[columnCount];
267: TableCellRenderer[] columnRenderers = new TableCellRenderer[columnCount];
268:
269: for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex) {
270: tableColumns[columnIndex] = columnModel
271: .getColumn(columnIndex);
272:
273: TableCellRenderer renderer = tableColumns[columnIndex]
274: .getCellRenderer();
275: if (renderer == null) {
276: Class columnClass = model
277: .getColumnClass(tableColumns[columnIndex]
278: .getModelIndex());
279: renderer = getDefaultRenderer(columnClass);
280: if (renderer == null) {
281: renderer = DEFAULT_TABLE_CELL_RENDERER;
282: }
283: }
284: columnRenderers[columnIndex] = renderer;
285:
286: }
287:
288: if (isHeaderVisible()) {
289: for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex) {
290: int modelColumnIndex = tableColumns[columnIndex]
291: .getModelIndex();
292: Object headerValue = tableColumns[columnIndex]
293: .getHeaderValue();
294: if (headerValue == null) {
295: headerValue = model.getColumnName(modelColumnIndex);
296: }
297: TableCellRenderer headerRenderer = tableColumns[columnIndex]
298: .getHeaderRenderer();
299: if (headerRenderer == null) {
300: headerRenderer = defaultHeaderRenderer;
301: if (headerRenderer == null) {
302: headerRenderer = DEFAULT_TABLE_CELL_RENDERER;
303: }
304: }
305: Component renderedComponent = headerRenderer
306: .getTableCellRendererComponent(this ,
307: headerValue, modelColumnIndex,
308: HEADER_ROW);
309: if (renderedComponent == null) {
310: renderedComponent = new Label();
311: }
312: add(renderedComponent);
313: }
314: }
315:
316: for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex) {
317: for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex) {
318: int modelColumnIndex = tableColumns[columnIndex]
319: .getModelIndex();
320: Object modelValue = model.getValueAt(modelColumnIndex,
321: rowIndex);
322: Component renderedComponent = columnRenderers[columnIndex]
323: .getTableCellRendererComponent(this ,
324: modelValue, modelColumnIndex, rowIndex);
325: if (renderedComponent == null) {
326: renderedComponent = new Label();
327: }
328: add(renderedComponent);
329: }
330: }
331: }
332:
333: /**
334: * Fires an action event to all listeners.
335: */
336: private void fireActionEvent() {
337: if (!hasEventListenerList()) {
338: return;
339: }
340: EventListener[] listeners = getEventListenerList()
341: .getListeners(ActionListener.class);
342: ActionEvent e = null;
343: for (int i = 0; i < listeners.length; ++i) {
344: if (e == null) {
345: e = new ActionEvent(
346: this ,
347: (String) getRenderProperty(PROPERTY_ACTION_COMMAND));
348: }
349: ((ActionListener) listeners[i]).actionPerformed(e);
350: }
351: }
352:
353: /**
354: * Returns the <code>Border</code>.
355: *
356: * @return the border
357: */
358: public Border getBorder() {
359: return (Border) getProperty(PROPERTY_BORDER);
360: }
361:
362: /**
363: * Returns the component rendered at the specified cell position.
364: * Invocation will automatically perform validation if required.
365: *
366: * @param column the column
367: * @param row the row
368: * @return the component
369: */
370: public Component getCellComponent(int column, int row) {
371: if (!valid) {
372: validate();
373: }
374: if (isHeaderVisible()) {
375: return getComponent((row + 1)
376: * columnModel.getColumnCount() + column);
377: } else {
378: if (row == HEADER_ROW) {
379: return null;
380: } else {
381: return getComponent(row * columnModel.getColumnCount()
382: + column);
383: }
384: }
385: }
386:
387: /**
388: * Returns the <code>TableColumnModel</code> describing this table's
389: * columns.
390: *
391: * @return the column model
392: */
393: public TableColumnModel getColumnModel() {
394: return columnModel;
395: }
396:
397: /**
398: * Returns the default <code>TableCellRenderer</code> used to render
399: * header cells. The default header renderer will be used in the event
400: * that a <code>TableColumn</code> does not provide a specific header
401: * renderer.
402: *
403: * @return the <code>TableCellRenderer</code>
404: */
405: public TableCellRenderer getDefaultHeaderRenderer() {
406: return defaultHeaderRenderer;
407: }
408:
409: /**
410: * Returns the default <code>TableCellRenderer</code> for the specified
411: * column class. The default renderer will be used in the event that
412: * a <code>TableColumn</code> does not provide a specific renderer.
413: *
414: * @param columnClass the column <code>Class</code>
415: * @return the <code>TableCellRenderer</code>
416: */
417: public TableCellRenderer getDefaultRenderer(Class columnClass) {
418: return (TableCellRenderer) defaultRendererMap.get(columnClass);
419: }
420:
421: /**
422: * Returns the default cell insets.
423: *
424: * @return the default cell insets
425: */
426: public Insets getInsets() {
427: return (Insets) getProperty(PROPERTY_INSETS);
428: }
429:
430: /**
431: * Returns the <code>TableModel</code> being visualized by this
432: * <code>Table</code>.
433: *
434: * @return the model
435: */
436: public TableModel getModel() {
437: return model;
438: }
439:
440: /**
441: * Return the rollover background color displayed when the mouse is within
442: * the bounds of a row.
443: *
444: * @return the color
445: */
446: public Color getRolloverBackground() {
447: return (Color) getProperty(PROPERTY_ROLLOVER_BACKGROUND);
448: }
449:
450: /**
451: * Return the rollover background image displayed when the mouse is within
452: * the bounds of a row.
453: *
454: * @return the background image
455: */
456: public FillImage getRolloverBackgroundImage() {
457: return (FillImage) getProperty(PROPERTY_ROLLOVER_BACKGROUND_IMAGE);
458: }
459:
460: /**
461: * Return the rollover font displayed when the mouse is within
462: * the bounds of a row.
463: *
464: * @return the font
465: */
466: public Font getRolloverFont() {
467: return (Font) getProperty(PROPERTY_ROLLOVER_FONT);
468: }
469:
470: /**
471: * Return the rollover foreground color displayed when the mouse is within
472: * the bounds of a row.
473: *
474: * @return the color
475: */
476: public Color getRolloverForeground() {
477: return (Color) getProperty(PROPERTY_ROLLOVER_FOREGROUND);
478: }
479:
480: /**
481: * Returns the row selection background color.
482: *
483: * @return the background color
484: */
485: public Color getSelectionBackground() {
486: return (Color) getProperty(PROPERTY_SELECTION_BACKGROUND);
487: }
488:
489: /**
490: * Returns the row selection background image.
491: *
492: * @return the background image
493: */
494: public FillImage getSelectionBackgroundImage() {
495: return (FillImage) getProperty(PROPERTY_SELECTION_BACKGROUND_IMAGE);
496: }
497:
498: /**
499: * Returns the row selection font.
500: *
501: * @return the font
502: */
503: public Font getSelectionFont() {
504: return (Font) getProperty(PROPERTY_SELECTION_FONT);
505: }
506:
507: /**
508: * Returns the row selection foreground color.
509: *
510: * @return the foreground color
511: */
512: public Color getSelectionForeground() {
513: return (Color) getProperty(PROPERTY_SELECTION_FOREGROUND);
514: }
515:
516: /**
517: * Returns the row selection model.
518: *
519: * @return the selection model
520: */
521: public ListSelectionModel getSelectionModel() {
522: return selectionModel;
523: }
524:
525: /**
526: * Returns the overall width of the grid.
527: * This property supports <code>Extent</code>s with
528: * fixed or percentile units.
529: *
530: * @return the width
531: */
532: public Extent getWidth() {
533: return (Extent) getProperty(PROPERTY_WIDTH);
534: }
535:
536: /**
537: * Determines the any <code>ActionListener</code>s are registered.
538: *
539: * @return true if any action listeners are registered
540: */
541: public boolean hasActionListeners() {
542: return getEventListenerList().getListenerCount(
543: ActionListener.class) != 0;
544: }
545:
546: /**
547: * Marks the table as needing to be re-rendered.
548: */
549: protected void invalidate() {
550: valid = false;
551: }
552:
553: /**
554: * Determines whether the <code>TableColumnModel</code> will be created
555: * automatically from the <code>TableModel</code>. If this flag is set,
556: * changes to the <code>TableModel</code> will automatically cause the
557: * <code>TableColumnModel</code> to be re-created. This flag is true
558: * by default unless a <code>TableColumnModel</code> is specified in the
559: * constructor.
560: *
561: * @return true if the <code>TableColumnModel</code> will be created
562: * automatically from the <code>TableModel</code>
563: */
564: public boolean isAutoCreateColumnsFromModel() {
565: return autoCreateColumnsFromModel;
566: }
567:
568: /**
569: * Determines if the table header is visible.
570: *
571: * @return the header visibility state
572: */
573: public boolean isHeaderVisible() {
574: return headerVisible;
575: }
576:
577: /**
578: * Determines if rollover effects are enabled.
579: *
580: * @return true if rollover effects are enabled
581: * @see #setRolloverEnabled(boolean)
582: */
583: public boolean isRolloverEnabled() {
584: Boolean value = (Boolean) getProperty(PROPERTY_ROLLOVER_ENABLED);
585: return value == null ? false : value.booleanValue();
586: }
587:
588: /**
589: * Determines if selection is enabled.
590: *
591: * @return true if selection is enabled
592: */
593: public boolean isSelectionEnabled() {
594: Boolean value = (Boolean) getProperty(PROPERTY_SELECTION_ENABLED);
595: return value == null ? false : value.booleanValue();
596: }
597:
598: /**
599: * @see nextapp.echo2.app.Component#processInput(java.lang.String, java.lang.Object)
600: */
601: public void processInput(String inputName, Object inputValue) {
602: super .processInput(inputName, inputValue);
603: if (inputName.equals(SELECTION_CHANGED_PROPERTY)) {
604: setSelectedIndices((int[]) inputValue);
605: } else if (INPUT_ACTION.equals(inputName)) {
606: fireActionEvent();
607: }
608: }
609:
610: /**
611: * Removes an <code>ActionListener</code> from the <code>Table</code>.
612: * <code>ActionListener</code>s will be invoked when the user
613: * selects a row.
614: *
615: * @param l the <code>ActionListener</code> to remove
616: */
617: public void removeActionListener(ActionListener l) {
618: if (!hasEventListenerList()) {
619: return;
620: }
621: getEventListenerList().removeListener(ActionListener.class, l);
622: // Notification of action listener changes is provided due to
623: // existence of hasActionListeners() method.
624: firePropertyChange(ACTION_LISTENERS_CHANGED_PROPERTY, l, null);
625: }
626:
627: /**
628: * Sets the action command which will be provided in
629: * <code>ActionEvent</code>s fired by this
630: * <code>Table</code>.
631: *
632: * @param newValue the new action command
633: */
634: public void setActionCommand(String newValue) {
635: setProperty(PROPERTY_ACTION_COMMAND, newValue);
636: }
637:
638: /**
639: * Sets whether the <code>TableColumnModel</code> will be created
640: * automatically from the <code>TableModel</code>.
641: *
642: * @param newValue true if the <code>TableColumnModel</code> should be
643: * created automatically from the <code>TableModel</code>
644: * @see #isAutoCreateColumnsFromModel()
645: */
646: public void setAutoCreateColumnsFromModel(boolean newValue) {
647: boolean oldValue = autoCreateColumnsFromModel;
648: autoCreateColumnsFromModel = newValue;
649:
650: if (!oldValue && newValue) {
651: createDefaultColumnsFromModel();
652: }
653:
654: firePropertyChange(
655: AUTO_CREATE_COLUMNS_FROM_MODEL_CHANGED_PROPERTY,
656: Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
657: }
658:
659: /**
660: * Sets the <code>Border</code>.
661: *
662: * @param newValue the new border
663: */
664: public void setBorder(Border newValue) {
665: setProperty(PROPERTY_BORDER, newValue);
666: }
667:
668: /**
669: * Sets the <code>TableColumnModel</code> describing this table's
670: * columns.
671: *
672: * @param newValue the new column model
673: */
674: public void setColumnModel(TableColumnModel newValue) {
675: invalidate();
676:
677: if (newValue == null) {
678: throw new IllegalArgumentException(
679: "The model may not be null.");
680: }
681:
682: TableColumnModel oldValue = columnModel;
683: if (oldValue != null) {
684: oldValue.removeColumnModelListener(columnModelListener);
685: }
686: columnModel = newValue;
687: newValue.addColumnModelListener(columnModelListener);
688: firePropertyChange(COLUMN_MODEL_CHANGED_PROPERTY, oldValue,
689: newValue);
690: }
691:
692: /**
693: * Sets the default <code>TableCellRenderer</code> used to render
694: * header cells. The default header renderer will be used in the event
695: * that a <code>TableColumn</code> does not provide a specific header
696: * renderer.
697: *
698: * @param newValue the <code>TableCellRenderer</code>
699: */
700: public void setDefaultHeaderRenderer(TableCellRenderer newValue) {
701: invalidate();
702: TableCellRenderer oldValue = defaultHeaderRenderer;
703: defaultHeaderRenderer = newValue;
704: firePropertyChange(DEFAULT_HEADER_RENDERER_CHANGED_PROPERTY,
705: oldValue, newValue);
706: }
707:
708: /**
709: * Sets the default <code>TableCellRenderer</code> for the specified
710: * column class. The default renderer will be used in the event that
711: * a <code>TableColumn</code> does not provide a specific renderer.
712: *
713: * @param columnClass the column <code>Class</code>
714: * @param newValue the <code>TableCellRenderer</code>
715: */
716: public void setDefaultRenderer(Class columnClass,
717: TableCellRenderer newValue) {
718: invalidate();
719: if (newValue == null) {
720: defaultRendererMap.remove(columnClass);
721: } else {
722: defaultRendererMap.put(columnClass, newValue);
723: }
724: firePropertyChange(DEFAULT_RENDERER_CHANGED_PROPERTY, null,
725: null);
726: }
727:
728: /**
729: * Sets the visibility state of the table header.
730: *
731: * @param newValue true if the header should be displayed
732: */
733: public void setHeaderVisible(boolean newValue) {
734: invalidate();
735: boolean oldValue = headerVisible;
736: headerVisible = newValue;
737: firePropertyChange(HEADER_VISIBLE_CHANGED_PROPERTY, Boolean
738: .valueOf(oldValue), Boolean.valueOf(newValue));
739: }
740:
741: /**
742: * Sets the default cell insets.
743: *
744: * @param newValue the new default cell insets
745: */
746: public void setInsets(Insets newValue) {
747: setProperty(PROPERTY_INSETS, newValue);
748: }
749:
750: /**
751: * Sets the <code>TableModel</code> being visualized.
752: *
753: * @param newValue the new model (may not be null)
754: */
755: public void setModel(TableModel newValue) {
756: invalidate();
757:
758: if (newValue == null) {
759: throw new IllegalArgumentException(
760: "The model may not be null.");
761: }
762:
763: TableModel oldValue = model;
764: if (oldValue != null) {
765: oldValue.removeTableModelListener(modelListener);
766: }
767: model = newValue;
768: newValue.addTableModelListener(modelListener);
769:
770: if (isAutoCreateColumnsFromModel()) {
771: createDefaultColumnsFromModel();
772: }
773:
774: firePropertyChange(MODEL_CHANGED_PROPERTY, oldValue, newValue);
775: }
776:
777: /**
778: * Sets the rollover background color displayed when the mouse is within
779: * the bounds of a row.
780: *
781: * @param newValue the new <code>Color</code>
782: */
783: public void setRolloverBackground(Color newValue) {
784: setProperty(PROPERTY_ROLLOVER_BACKGROUND, newValue);
785: }
786:
787: /**
788: * Sets the rollover background image displayed when the mouse is within
789: * the bounds of a row.
790: *
791: * @param newValue the new background image
792: */
793: public void setRolloverBackgroundImage(FillImage newValue) {
794: setProperty(PROPERTY_ROLLOVER_BACKGROUND_IMAGE, newValue);
795: }
796:
797: /**
798: * Sets whether rollover effects are enabled when the mouse cursor is
799: * within the bounds of a row. Rollover properties have no effect unless
800: * this property is set to true. The default value is false.
801: *
802: * @param newValue true if rollover effects should be enabled
803: */
804: public void setRolloverEnabled(boolean newValue) {
805: setProperty(PROPERTY_ROLLOVER_ENABLED, new Boolean(newValue));
806: }
807:
808: /**
809: * Sets the rollover font displayed when the mouse is within
810: * the bounds of a row.
811: *
812: * @param newValue the new <code>Font</code>
813: */
814: public void setRolloverFont(Font newValue) {
815: setProperty(PROPERTY_ROLLOVER_FONT, newValue);
816: }
817:
818: /**
819: * Sets the rollover foreground color displayed when the mouse is within
820: * the bounds of a row.
821: *
822: * @param newValue the new <code>Color</code>
823: */
824: public void setRolloverForeground(Color newValue) {
825: setProperty(PROPERTY_ROLLOVER_FOREGROUND, newValue);
826: }
827:
828: /**
829: * Selects only the specified row indices.
830: *
831: * @param selectedIndices the indices to select
832: */
833: private void setSelectedIndices(int[] selectedIndices) {
834: // Temporarily suppress the Tables selection event notifier.
835: suppressChangeNotifications = true;
836: ListSelectionModel selectionModel = getSelectionModel();
837: selectionModel.clearSelection();
838: for (int i = 0; i < selectedIndices.length; ++i) {
839: selectionModel.setSelectedIndex(selectedIndices[i], true);
840: }
841: // End temporary suppression.
842: suppressChangeNotifications = false;
843: firePropertyChange(SELECTION_CHANGED_PROPERTY, null,
844: selectedIndices);
845: }
846:
847: /**
848: * Sets the row selection background color.
849: *
850: * @param newValue the new background color
851: */
852: public void setSelectionBackground(Color newValue) {
853: setProperty(PROPERTY_SELECTION_BACKGROUND, newValue);
854: }
855:
856: /**
857: * Sets the row selection background image.
858: *
859: * @param newValue the new background image
860: */
861: public void setSelectionBackgroundImage(FillImage newValue) {
862: setProperty(PROPERTY_SELECTION_BACKGROUND_IMAGE, newValue);
863: }
864:
865: /**
866: * Sets whether selection is enabled.
867: *
868: * @param newValue true to enable selection
869: */
870: public void setSelectionEnabled(boolean newValue) {
871: setProperty(PROPERTY_SELECTION_ENABLED, Boolean
872: .valueOf(newValue));
873: }
874:
875: /**
876: * Sets the row selection foreground color.
877: *
878: * @param newValue the new foreground color
879: */
880: public void setSelectionForeground(Color newValue) {
881: setProperty(PROPERTY_SELECTION_FOREGROUND, newValue);
882: }
883:
884: /**
885: * Sets the row selection font.
886: *
887: * @param newValue the new font
888: */
889: public void setSelectionFont(Font newValue) {
890: setProperty(PROPERTY_SELECTION_FONT, newValue);
891: }
892:
893: /**
894: * Sets the row selection model.
895: * The selection model may not be null.
896: *
897: * @param newValue the new selection model
898: */
899: public void setSelectionModel(ListSelectionModel newValue) {
900: if (newValue == null) {
901: throw new IllegalArgumentException(
902: "Selection model may not be null.");
903: }
904: ListSelectionModel oldValue = selectionModel;
905: if (oldValue != null) {
906: oldValue.removeChangeListener(changeHandler);
907: }
908: newValue.addChangeListener(changeHandler);
909: selectionModel = newValue;
910: firePropertyChange(SELECTION_MODEL_CHANGED_PROPERTY, oldValue,
911: newValue);
912: }
913:
914: /**
915: * Sets the overall width of the grid.
916: * This property supports <code>Extent</code>s with
917: * fixed or percentile units.
918: *
919: * @param newValue the new width
920: */
921: public void setWidth(Extent newValue) {
922: setProperty(PROPERTY_WIDTH, newValue);
923: }
924:
925: /**
926: * @see nextapp.echo2.app.Component#validate()
927: */
928: public void validate() {
929: super .validate();
930: while (!valid) {
931: valid = true;
932: doRender();
933: }
934: }
935: }
|