0001: /*
0002: * Copyright 2000,2005 wingS development team.
0003: *
0004: * This file is part of wingS (http://wingsframework.org).
0005: *
0006: * wingS is free software; you can redistribute it and/or modify
0007: * it under the terms of the GNU Lesser General Public License
0008: * as published by the Free Software Foundation; either version 2.1
0009: * of the License, or (at your option) any later version.
0010: *
0011: * Please see COPYING for the complete licence.
0012: */
0013: package org.wings;
0014:
0015: import org.apache.commons.logging.Log;
0016: import org.apache.commons.logging.LogFactory;
0017: import org.wings.event.*;
0018: import org.wings.plaf.TableCG;
0019: import org.wings.style.*;
0020: import org.wings.table.*;
0021: import org.wings.util.SStringBuilder;
0022:
0023: import javax.swing.event.*;
0024: import javax.swing.table.DefaultTableModel;
0025: import javax.swing.table.TableModel;
0026: import java.awt.*;
0027: import java.util.*;
0028: import java.util.List;
0029:
0030: /**
0031: * Displays information contained in a {@link TableModel} object.
0032: *
0033: * @author <a href="mailto:engels@mercatis.de">Holger Engels</a>
0034: * @author <a href="mailto:haaf@mercatis.de">Armin Haaf</a>
0035: */
0036: public class STable extends SComponent implements TableModelListener,
0037: Scrollable, CellEditorListener, LowLevelEventListener {
0038:
0039: /**
0040: * Apache jakarta commons logger
0041: */
0042: private final static Log log = LogFactory.getLog(STable.class);
0043:
0044: /**
0045: * Table selection model. See {@link STable#setSelectionMode(int)}
0046: */
0047: public static final int NO_SELECTION = SListSelectionModel.NO_SELECTION;
0048: /**
0049: * Table selection model. See {@link STable#setSelectionMode(int)}
0050: */
0051: public static final int SINGLE_SELECTION = SListSelectionModel.SINGLE_SELECTION;
0052: /**
0053: * Table selection model. See {@link STable#setSelectionMode(int)}
0054: */
0055: public static final int SINGLE_INTERVAL_SELECTION = SListSelectionModel.SINGLE_INTERVAL_SELECTION;
0056: /**
0057: * Table selection model. See {@link STable#setSelectionMode(int)}
0058: */
0059: public static final int MULTIPLE_SELECTION = SListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
0060: /**
0061: * Table selection model. See {@link STable#setSelectionMode(int)}
0062: */
0063: public static final int MULTIPLE_INTERVAL_SELECTION = SListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
0064:
0065: /**
0066: * <p>the table model.</p>
0067: */
0068: protected TableModel model;
0069:
0070: /**
0071: * <p>the selection model.</p>
0072: */
0073: protected SListSelectionModel selectionModel;
0074:
0075: /**
0076: * <p>The default renderer is used if no other renderer is set for the
0077: * content of a cell.</p>
0078: */
0079: protected STableCellRenderer defaultRenderer;
0080:
0081: /**
0082: * <p>The <code>headerRenderer</code> is used to render the header line.</p>
0083: */
0084: protected STableCellRenderer headerRenderer;
0085:
0086: /**
0087: * <p>A special cell renderer, that displays the control used to select
0088: * a table row.</p><p>Ususally, this would be some checkbox. The plaf is the
0089: * last instance to decide this.</p>
0090: */
0091: protected STableCellRenderer rowSelectionRenderer;
0092:
0093: /**
0094: * <p>In this <code>Map</code>, the renderers for the different
0095: * classes of cell content are stored.</p><p>The class is treated
0096: * as key, the renderer as the value.</p>
0097: */
0098: protected final HashMap renderer = new HashMap();
0099:
0100: /**
0101: * If this table is editable, clicks on table cells will be catched and interpreted as
0102: * editor calls. Otherwise they may result in a selection event if {@link #isSelectable()}
0103: */
0104: protected boolean editable = true;
0105:
0106: /**
0107: * If this table is marked as selectable, clicks on non-editable table cells will
0108: * be catched and interpreted as selection calls.
0109: */
0110: protected boolean selectable = true;
0111:
0112: /**
0113: * <p>If editing, this is the <code>SComponent</code> that is handling the editing.
0114: */
0115: transient protected SComponent editorComp;
0116:
0117: /**
0118: * <p>The object that overwrites the screen real estate occupied by the
0119: * current cell and allows the user to change those contents.</p>
0120: */
0121: transient protected STableCellEditor cellEditor;
0122:
0123: transient protected LowLevelEventListener cellEditorComponent;
0124: /**
0125: * <p>Identifies the column of the cell being edited.</p>
0126: */
0127: transient protected int editingColumn = -1;
0128:
0129: /**
0130: * <p>Identifies the row of the cell being edited.</p>
0131: */
0132: transient protected int editingRow = -1;
0133:
0134: /**
0135: * <p>In this <code>Map</code>, the <code>STableCellEditor</code>s for the different
0136: * classes of cell content are stored.</p><p>The class is treated
0137: * as key, the <code>STableCellEditor</code> as the value.</p>
0138: */
0139: protected final HashMap editors = new HashMap();
0140:
0141: /**
0142: * <p>Determines whether the header is visible or not.</p><p>By
0143: * default the header is visible.</p> <p><em>CAVEAT:</em>The
0144: * header is not (yet) implemented like in Swing. But maybe
0145: * someday. So you can disable it if you like.</p>
0146: */
0147: protected boolean headerVisible = true;
0148:
0149: /**
0150: * <p>Determines if horizontal lines in the table should be
0151: * painted.</p><p>This is off by default.</p>
0152: */
0153: protected boolean showHorizontalLines = false;
0154:
0155: /**
0156: * <p>Determines if vertical lines in the table should be
0157: * painted.</p><p>This is off by default.</p>
0158: */
0159: protected boolean showVerticalLines = false;
0160:
0161: protected SDimension intercellSpacing;
0162:
0163: protected SDimension intercellPadding = new SDimension("1", "1");
0164:
0165: /**
0166: * Implementation of the {@link Scrollable} interface.
0167: */
0168: protected Rectangle viewport;
0169:
0170: /**
0171: * Used to detect if the number of rows changed in
0172: * which case we might have to update the viewport.
0173: */
0174: private int rowCountBackUp;
0175:
0176: /**
0177: * Used to detect if the number of columns changed in
0178: * which case we might have to update the viewport.
0179: */
0180: private int columnCountBackUp;
0181:
0182: /**
0183: * @see LowLevelEventListener#isEpochCheckEnabled()
0184: */
0185: protected boolean epochCheckEnabled = true;
0186:
0187: /**
0188: * The column model holds state information about the columns of the table.
0189: */
0190: protected STableColumnModel columnModel;
0191:
0192: transient protected STableColumnModelListener tableColumnModelListener;
0193:
0194: /**
0195: * If true, the column model is autorebuild from the table model.
0196: */
0197: private boolean autoCreateColumnsFromModel;
0198:
0199: /**
0200: * A Pseudo CSS selector addressing the header row elements.
0201: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0202: */
0203: public static final Selector SELECTOR_HEADER = new Selector(
0204: "HEADER");
0205:
0206: /**
0207: * A Pseudo CSS selector addressing the selected row elements.
0208: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0209: */
0210: public static final Selector SELECTOR_SELECTED = new Selector(
0211: "SELECTED");
0212:
0213: /**
0214: * A Pseudo CSS selector addressing the regular odd row elements.
0215: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0216: */
0217: public static final Selector SELECTOR_ODD_ROWS = new Selector(
0218: "ODD_ROWS");
0219:
0220: /**
0221: * A Pseudo CSS selector addressing the regular even row elements.
0222: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0223: */
0224: public static final Selector SELECTOR_EVEN_ROWS = new Selector(
0225: "EVEN_ROWS");
0226:
0227: /**
0228: * The last low level event values this table received.
0229: */
0230: private String[] lastReceivedLowLevelEvents;
0231:
0232: /**
0233: * Helper variable for {@link #nameRendererComponent(SComponent, int, int)}
0234: */
0235: private SStringBuilder nameBuffer = new SStringBuilder();
0236:
0237: /**
0238: * changes in the selection model should force a reload if possible
0239: */
0240: protected final ListSelectionListener fwdSelectionEvents = new ListSelectionListener() {
0241:
0242: List<Integer> deselectedIndices;
0243: List<Integer> selectedIndices;
0244:
0245: public void valueChanged(ListSelectionEvent e) {
0246: if (isUpdatePossible()
0247: && STable.class.isAssignableFrom(STable.this
0248: .getClass())) {
0249: deselectedIndices = new ArrayList<Integer>();
0250: selectedIndices = new ArrayList<Integer>();
0251: if (getSelectionMode() == SINGLE_SELECTION) {
0252: addIndex(e.getFirstIndex());
0253: addIndex(e.getLastIndex());
0254: } else {
0255: for (int index = e.getFirstIndex(); index <= e
0256: .getLastIndex(); ++index) {
0257: addIndex(index);
0258: }
0259: }
0260: update(((TableCG) getCG())
0261: .getSelectionUpdate(STable.this ,
0262: deselectedIndices, selectedIndices));
0263: } else {
0264: reload();
0265: }
0266: }
0267:
0268: private void addIndex(int index) {
0269: int visibleIndex = index;
0270: if (getViewportSize() != null) {
0271: visibleIndex = index - getViewportSize().y;
0272: if (visibleIndex < 0
0273: || visibleIndex >= getViewportSize().height)
0274: return;
0275: }
0276: if (isRowSelected(index)) {
0277: selectedIndices.add(new Integer(visibleIndex));
0278: } else {
0279: deselectedIndices.add(new Integer(visibleIndex));
0280: }
0281: }
0282: };
0283:
0284: /**
0285: * <p>
0286: * Creates a new <code>STable</code>.
0287: * </p>
0288: */
0289: public STable() {
0290: this (null);
0291: }
0292:
0293: /**
0294: * <p>Creates a new <code>STable</code>.</p>
0295: *
0296: * @param tm the <code>TableModel</code> for the table's contents.
0297: */
0298: public STable(TableModel tm) {
0299: this (tm, null);
0300: }
0301:
0302: /**
0303: * <p>Creates a new <code>STable</code>.</p>
0304: *
0305: * @param model the <code>TableModel</code> for the table's contents. May be <code>null</code>.
0306: * @param columnModel The column model. Implicitly created and maintained if <code>null</code>.
0307: */
0308: public STable(TableModel model, STableColumnModel columnModel) {
0309: setSelectionModel(new SDefaultListSelectionModel());
0310: createDefaultEditors();
0311:
0312: if (columnModel == null) {
0313: // no issue if model == null!
0314: columnModel = createDefaultColumnModel();
0315: autoCreateColumnsFromModel = true;
0316: }
0317: setColumnModel(columnModel);
0318:
0319: if (model == null)
0320: model = createDefaultDataModel();
0321: setModel(model); // the resulting tableChanged event will update the default column mdoel
0322: }
0323:
0324: /**
0325: * <p>Sets the model of the table.</p>
0326: *
0327: * @param tm the <code>TableModel</code> to set.
0328: */
0329: public void setModel(TableModel tm) {
0330: if (tm == null)
0331: throw new IllegalArgumentException(
0332: "Cannot set a null TableModel");
0333:
0334: if (this .model != tm) {
0335: if (model != null)
0336: model.removeTableModelListener(this );
0337:
0338: model = tm;
0339: model.addTableModelListener(this );
0340:
0341: tableChanged(new TableModelEvent(tm,
0342: TableModelEvent.HEADER_ROW));
0343: }
0344: }
0345:
0346: /**
0347: * <p>returns the model of the table</p>
0348: */
0349: public TableModel getModel() {
0350: return model;
0351: }
0352:
0353: public int getColumnCount() {
0354: return model.getColumnCount();
0355: }
0356:
0357: public int getVisibleColumnCount() {
0358: if (columnModel != null) {
0359: int columnCount = 0;
0360: for (Iterator iterator = columnModel.getColumns()
0361: .iterator(); iterator.hasNext();) {
0362: STableColumn tableColumn = (STableColumn) iterator
0363: .next();
0364: if (!tableColumn.isHidden())
0365: columnCount++;
0366: }
0367: return columnCount;
0368: } else
0369: return model.getColumnCount();
0370: }
0371:
0372: public String getColumnName(int col) {
0373: return model.getColumnName(convertColumnIndexToModel(col));
0374: }
0375:
0376: public Class getColumnClass(int col) {
0377: return model.getColumnClass(convertColumnIndexToModel(col));
0378: }
0379:
0380: /**
0381: * Convienece method / Swing compatiblity to <code>model.getRowCount()</code>
0382: * @return numer of rows inside the table model
0383: */
0384: public int getRowCount() {
0385: return model.getRowCount();
0386: }
0387:
0388: /**
0389: * Define an optional CSS class which should be applied additionally to the passed row num.
0390: * Override this method, if you want to give rows different attributes.
0391: * E.g. for displaying an alternating background color for rows.
0392: *
0393: * @return the style of a specific row number.
0394: */
0395: public String getRowStyle(int row) {
0396: return null;
0397: }
0398:
0399: public Object getValueAt(int row, int column) {
0400: return model.getValueAt(row, convertColumnIndexToModel(column));
0401: }
0402:
0403: public void setValueAt(Object v, int row, int column) {
0404: model.setValueAt(v, row, convertColumnIndexToModel(column));
0405: }
0406:
0407: public int convertColumnIndexToModel(int viewColumnIndex) {
0408: if (viewColumnIndex < 0) {
0409: return viewColumnIndex;
0410: }
0411: return getColumnModel().getColumn(viewColumnIndex)
0412: .getModelIndex();
0413: }
0414:
0415: /**
0416: * Maps the index of the column in the table model at
0417: * <code>modelColumnIndex</code> to the index of the column
0418: * in the view. Returns the index of the
0419: * corresponding column in the view; returns -1 if this column is not
0420: * being displayed. If <code>modelColumnIndex</code> is less than zero,
0421: * returns <code>modelColumnIndex</code>.
0422: *
0423: * @param modelColumnIndex the index of the column in the model
0424: * @return the index of the corresponding column in the view
0425: *
0426: * @see #convertColumnIndexToModel
0427: */
0428: public int convertColumnIndexToView(int modelColumnIndex) {
0429: if (modelColumnIndex < 0) {
0430: return modelColumnIndex;
0431: }
0432: STableColumnModel cm = getColumnModel();
0433: int count = cm.getColumnCount();
0434: for (int column = 0; column < count; column++) {
0435: if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
0436: return column;
0437: }
0438: }
0439: return -1;
0440: }
0441:
0442: /**
0443: * Adds the row from <i>index0</i> to <i>index0</i> inclusive to the current selection.
0444: */
0445: public void addRowSelectionInterval(int index0, int index1) {
0446: selectionModel.addSelectionInterval(index0, index1);
0447: }
0448:
0449: /**
0450: * Sets the container, this component resides in.
0451: *
0452: * @param p the container, this component resides in.
0453: */
0454: public void setParent(SContainer p) {
0455: super .setParent(p);
0456:
0457: if (getCellRendererPane() != null) {
0458: getCellRendererPane().setParent(p);
0459: }
0460:
0461: if (editorComp != null) {
0462: editorComp.setParent(p);
0463: }
0464: }
0465:
0466: /**
0467: * Sets the frame in which this component resides.
0468: *
0469: * @param f the frame in which this component resides.
0470: */
0471: protected void setParentFrame(SFrame f) {
0472: super .setParentFrame(f);
0473: if (getCellRendererPane() != null) {
0474: getCellRendererPane().setParentFrame(f);
0475: }
0476: }
0477:
0478: // check fireIntermediateEvents !
0479: public void processLowLevelEvent(String action, String[] values) {
0480: processKeyEvents(values);
0481: if (action.endsWith("_keystroke"))
0482: return;
0483:
0484: if (isEditing() && action.indexOf("_e_") != -1
0485: && cellEditorComponent != null) {
0486: cellEditorComponent.processLowLevelEvent(action, values);
0487: } else {
0488: if (this .lastReceivedLowLevelEvents == null) {
0489: this .lastReceivedLowLevelEvents = values;
0490: } else if (values != null && values.length > 0) {
0491: // more than one parameter targets the table. collecting parameter values
0492: String[] joinedParameters = new String[this .lastReceivedLowLevelEvents.length
0493: + values.length];
0494: System.arraycopy(this .lastReceivedLowLevelEvents, 0,
0495: joinedParameters, 0,
0496: this .lastReceivedLowLevelEvents.length);
0497: System.arraycopy(values, 0, joinedParameters,
0498: this .lastReceivedLowLevelEvents.length,
0499: values.length);
0500: this .lastReceivedLowLevelEvents = joinedParameters;
0501: }
0502: }
0503:
0504: SForm.addArmedComponent(this );
0505: }
0506:
0507: private SCellRendererPane cellRendererPane = new SCellRendererPane();
0508:
0509: public SCellRendererPane getCellRendererPane() {
0510: return cellRendererPane;
0511: }
0512:
0513: /**
0514: * Sets <p>The default renderer is used if no other renderer is set for the
0515: * content of a cell.</p>
0516: *
0517: * @param r <p>The default renderer is used if no other renderer is set for the
0518: */
0519: public void setDefaultRenderer(STableCellRenderer r) {
0520: defaultRenderer = r;
0521: }
0522:
0523: /**
0524: * Returns <p>The default renderer is used if no other renderer is set for the
0525: * content of a cell.</p>
0526: *
0527: * @return <p>The default renderer is used if no other renderer is set for the
0528: */
0529: public STableCellRenderer getDefaultRenderer() {
0530: return defaultRenderer;
0531: }
0532:
0533: public void setDefaultRenderer(Class columnClass,
0534: STableCellRenderer r) {
0535: if (renderer != null) {
0536: renderer.remove(columnClass);
0537: renderer.put(columnClass, r);
0538: }
0539: }
0540:
0541: public STableCellRenderer getDefaultRenderer(Class columnClass) {
0542: if (columnClass == null) {
0543: return defaultRenderer;
0544: } else {
0545: Object r = renderer.get(columnClass);
0546: if (r != null) {
0547: return (STableCellRenderer) r;
0548: } else {
0549: return getDefaultRenderer(columnClass.getSuperclass());
0550: }
0551: }
0552: }
0553:
0554: /**
0555: * The renderer component responsible for rendering the table's header cell.
0556: * @param headerCellRenderer
0557: */
0558: public void setHeaderRenderer(STableCellRenderer headerCellRenderer) {
0559: headerRenderer = headerCellRenderer;
0560: }
0561:
0562: /**
0563: * The renderer component responsible for rendering the table's header cell.
0564: * @return The renderer component for the header row
0565: */
0566: public STableCellRenderer getHeaderRenderer() {
0567: return headerRenderer;
0568: }
0569:
0570: /**
0571: * The cell renderer used to render a special selection column needed in cases clicks on table
0572: * cell cannot be distinguished as 'edit' or 'selection' click.
0573: * @return The table cell renderer used to render the selection column, or <code>null</code>
0574: * if no selection row should be rendered.
0575: */
0576: public STableCellRenderer getRowSelectionRenderer() {
0577: return rowSelectionRenderer;
0578: }
0579:
0580: /**
0581: * The cell renderer used to render a special selection column needed in cases clicks on table
0582: * cell cannot be distinguished as 'edit' or 'selection' click.
0583: * @param rowSelectionRenderer The table cell renderer used to render the selection column.
0584: * Set this to <code>null</code> if you don't want to have a selection row in any case
0585: */
0586: public void setRowSelectionRenderer(
0587: STableCellRenderer rowSelectionRenderer) {
0588: this .rowSelectionRenderer = rowSelectionRenderer;
0589: }
0590:
0591: /**
0592: * Returns the cell renderer for the given table cell.
0593: * @param row Table row
0594: * @param col Table column
0595: * @return The cell renderer for the given table cell.
0596: */
0597: public STableCellRenderer getCellRenderer(int row, int col) {
0598: STableColumnModel columnModel = getColumnModel();
0599: if (columnModel != null) {
0600: STableColumn column = columnModel.getColumn(col);
0601: if (column != null) {
0602: STableCellRenderer renderer = column.getCellRenderer();
0603: if (renderer != null)
0604: return renderer;
0605: }
0606: }
0607: return getDefaultRenderer(getColumnClass(col));
0608: }
0609:
0610: /**
0611: * Returns the header renderer for the given header cell.
0612: * @param col Table column
0613: * @return The header renderer for the given header cell.
0614: */
0615: public STableCellRenderer getHeaderRenderer(int col) {
0616: STableColumnModel columnModel = getColumnModel();
0617: if (columnModel != null) {
0618: STableColumn column = columnModel.getColumn(col);
0619: if (column != null) {
0620: STableCellRenderer renderer = column
0621: .getHeaderRenderer();
0622: if (renderer != null)
0623: return renderer;
0624: }
0625: }
0626: return getHeaderRenderer();
0627: }
0628:
0629: public SComponent prepareRenderer(STableCellRenderer r, int row,
0630: int col) {
0631: final SComponent tableCellRendererComponent = r
0632: .getTableCellRendererComponent(this , getValueAt(row,
0633: col), isRowSelected(row), row, col);
0634: nameRendererComponent(tableCellRendererComponent, row, col);
0635: return tableCellRendererComponent;
0636: }
0637:
0638: /**
0639: * Generates the name (= id) of the editing component so that
0640: * the STable implementation knows to associate the input
0641: * value with the correct data row/columns
0642: *
0643: * Applies the unqique id/name for a component of the rows/column
0644: * to the cell component.
0645: *
0646: * @param component The edit component to rename
0647: * @param row Data row of this edit component
0648: * @param col Data column of this edit component
0649: */
0650: protected void nameRendererComponent(final SComponent component,
0651: final int row, final int col) {
0652: nameBuffer.setLength(0);
0653: nameBuffer.append(this .getName()).append('_');
0654: if (row == -1)
0655: nameBuffer.append('h');
0656: else
0657: nameBuffer.append(row);
0658: nameBuffer.append('_').append(col);
0659: component.setNameRaw(nameBuffer.toString());
0660: }
0661:
0662: /**
0663: * Prepares and returns the renderer to render the column header
0664: * @param col Column number to render. Starts with <code>0</code>. May be <code>-1</code> for row selection column.
0665: * @return The renderer to render the column header
0666: */
0667: public SComponent prepareHeaderRenderer(
0668: STableCellRenderer headerRenderer, int col) {
0669: Object headerValue;
0670: if (col < 0) {
0671: headerValue = null;
0672: } else if (getColumnModel() != null
0673: && getColumnModel().getColumn(col) != null) {
0674: headerValue = getColumnModel().getColumn(col)
0675: .getHeaderValue();
0676: } else {
0677: headerValue = model.getColumnName(col);
0678: }
0679: return headerRenderer.getTableCellRendererComponent(this ,
0680: headerValue, false, -1, col);
0681: }
0682:
0683: /**
0684: * If this table is editable, clicks on table cells will be catched and interpreted as
0685: * editor calls. Otherwise they may result in a selection event if {@link #isSelectable()}
0686: * <p>Defaults to <code>true</code>
0687: *
0688: * @return <code>true</code> if clicks on editable cell should trigger the cell editor,
0689: * <code>false</code> if never.
0690: */
0691: public boolean isEditable() {
0692: return editable;
0693: }
0694:
0695: /**
0696: * If this table is editable, clicks on table cells will be catched
0697: * as {@link org.wings.event.SMouseEvent}s and interpreted as
0698: * editor calls. Otherwise they may result in a selection event if {@link #isSelectable()}.
0699: * <p>Defaults to <code>true</code>
0700: *
0701: * @param editable <code>true</code> if clicks on editable cell should trigger the cell editor,
0702: * <code>false</code> if never.
0703: * @see #isEditable()
0704: * @see #processLowLevelEvent(String, String[])
0705: * @see #fireIntermediateEvents()
0706: */
0707: public void setEditable(boolean editable) {
0708: reloadIfChange(this .editable, editable);
0709: this .editable = editable;
0710: }
0711:
0712: /**
0713: * If this table is marked as selectable, clicks on a non-editable table cells
0714: * {@link #setEditable(boolean)} must be <code>false</code>) will be catched
0715: * as {@link org.wings.event.SMouseEvent}s and interpreted as selection calls.
0716: * <p>Defaults to <code>true</code>
0717: *
0718: * @return <code>true</code> if table cell should catch clicks on non-editable tables.
0719: */
0720: public boolean isSelectable() {
0721: return selectable;
0722: }
0723:
0724: /**
0725: * If this table is marked as selectable, clicks on a non-editable table cells
0726: * {@link #setEditable(boolean)} must be <code>false</code>) will be catched
0727: * as {@link org.wings.event.SMouseEvent}s and interpreted as selection calls.
0728: * <p>Defaults to <code>true</code>
0729: *
0730: * @param selectable <code>true</code> if table cell should catch clicks on non-editable tables.
0731: * @see #isEditable()
0732: * @see #processLowLevelEvent(String, String[])
0733: * @see #fireIntermediateEvents()
0734: */
0735: public void setSelectable(boolean selectable) {
0736: reloadIfChange(this .selectable, selectable);
0737: this .selectable = selectable;
0738: }
0739:
0740: /**
0741: * Set a default editor to be used if no editor has been set in
0742: * a TableColumn. If no editing is required in a table, or a
0743: * particular column in a table, use the isCellEditable()
0744: * method in the TableModel interface to ensure that the
0745: * STable will not start an editor in these columns.
0746: * If editor is null, remove the default editor for this
0747: * column class.
0748: *
0749: * @see TableModel#isCellEditable
0750: * @see #getDefaultEditor
0751: * @see #setDefaultRenderer
0752: */
0753: public void setDefaultEditor(Class columnClass, STableCellEditor r) {
0754: if (editors != null) {
0755: editors.remove(columnClass);
0756: editors.put(columnClass, r);
0757: }
0758: }
0759:
0760: /*
0761: * Returns the editor to be used when no editor has been set in
0762: * a TableColumn. During the editing of cells the editor is fetched from
0763: * a Map of entries according to the class of the cells in the column. If
0764: * there is no entry for this <I>columnClass</I> the method returns
0765: * the entry for the most specific superclass. The STable installs entries
0766: * for <I>Object</I>, <I>Number</I> and <I>Boolean</I> all which can be modified
0767: * or replaced.
0768: *
0769: * @see #setDefaultEditor
0770: * @see #getColumnClass
0771: */
0772: public STableCellEditor getDefaultEditor(Class columnClass) {
0773: if (columnClass == null) {
0774: return null;
0775: } else {
0776: Object r = editors.get(columnClass);
0777: if (r != null) {
0778: return (STableCellEditor) r;
0779: } else {
0780: return getDefaultEditor(columnClass.getSuperclass());
0781: }
0782: }
0783: }
0784:
0785: //
0786: // Editing Support
0787: //
0788:
0789: /**
0790: * Programmatically starts editing the cell at <I>row</I> and
0791: * <I>column</I>, if the cell is editable.
0792: *
0793: * @param row the row to be edited
0794: * @param column the column to be edited
0795: * @return false if for any reason the cell cannot be edited.
0796: * @throws IllegalArgumentException If <I>row</I> or <I>column</I>
0797: * are not in the valid range
0798: */
0799: public boolean editCellAt(int row, int column) {
0800: return editCellAt(row, column, null);
0801: }
0802:
0803: /**
0804: * Programmatically starts editing the cell at <I>row</I> and
0805: * <I>column</I>, if the cell is editable.
0806: * To prevent the STable from editing a particular table, column or
0807: * cell value, return false from the isCellEditable() method in the
0808: * TableModel interface.
0809: *
0810: * @param row the row to be edited
0811: * @param column the column to be edited
0812: * @param e event to pass into
0813: * shouldSelectCell
0814: * @return false if for any reason the cell cannot be edited.
0815: * @throws IllegalArgumentException If <I>row</I> or <I>column</I>
0816: * are not in the valid range
0817: */
0818: public boolean editCellAt(int row, int column, EventObject e) {
0819: if (isEditing()) {
0820: // Try to stop the current editor
0821: if (cellEditor != null) {
0822: boolean stopped = cellEditor.stopCellEditing();
0823: if (!stopped)
0824: return false; // The current editor not resigning
0825: }
0826: }
0827:
0828: if (!isCellEditable(row, column))
0829: return false;
0830:
0831: STableCellEditor editor = getCellEditor(row, column);
0832: if (editor != null) {
0833: // set up editor environment and make it possible for the editor, to
0834: // stop/cancel editing on preparation
0835: editor.addCellEditorListener(this );
0836: setCellEditor(editor);
0837: setEditingRow(row);
0838: setEditingColumn(column);
0839:
0840: // prepare editor
0841: editorComp = prepareEditor(editor, row, column);
0842:
0843: if (editor.isCellEditable(e) && editor.shouldSelectCell(e)) {
0844: update(((TableCG) getCG()).getEditCellUpdate(this , row,
0845: column));
0846: return true;
0847: } else {
0848: setValueAt(editor.getCellEditorValue(), row, column);
0849: removeEditor();
0850: }
0851: }
0852: return false;
0853: }
0854:
0855: /**
0856: * Returns true if the cell at <I>row</I> and <I>column</I>
0857: * is editable. Otherwise, setValueAt() on the cell will not change
0858: * the value of that cell.
0859: *
0860: * @param row the row whose value is to be looked up
0861: * @param col the column whose value is to be looked up
0862: * @return true if the cell is editable.
0863: * @see #setValueAt
0864: */
0865: public boolean isCellEditable(int row, int col) {
0866: if (col >= getColumnCount() || row == -1)
0867: return false;
0868: else
0869: return getModel().isCellEditable(row,
0870: convertColumnIndexToModel(col));
0871: }
0872:
0873: /**
0874: * Returns true is the table is editing a cell.
0875: *
0876: * @return true is the table is editing a cell
0877: * @see #editingColumn
0878: * @see #editingRow
0879: */
0880: public boolean isEditing() {
0881: return (cellEditor != null);
0882: }
0883:
0884: /**
0885: * If the receiver is currently editing this will return the Component
0886: * that was returned from the CellEditor.
0887: *
0888: * @return SComponent handling editing session
0889: */
0890: public SComponent getEditorComponent() {
0891: return editorComp;
0892: }
0893:
0894: /**
0895: * This returns the index of the editing column.
0896: *
0897: * @return the index of the column being edited
0898: * @see #editingRow
0899: */
0900: public int getEditingColumn() {
0901: return editingColumn;
0902: }
0903:
0904: /**
0905: * Returns the index of the editing row.
0906: *
0907: * @return the index of the row being edited
0908: * @see #editingColumn
0909: */
0910: public int getEditingRow() {
0911: return editingRow;
0912: }
0913:
0914: /**
0915: * Return the cellEditor.
0916: *
0917: * @return the STableCellEditor that does the editing
0918: * @see #cellEditor
0919: */
0920: public STableCellEditor getCellEditor() {
0921: return cellEditor;
0922: }
0923:
0924: /**
0925: * Set the cellEditor variable.
0926: *
0927: * @param anEditor the STableCellEditor that does the editing
0928: * @see #cellEditor
0929: */
0930: protected void setCellEditor(STableCellEditor anEditor) {
0931: cellEditor = anEditor;
0932: }
0933:
0934: /**
0935: * Set the editingColumn variable.
0936: *
0937: * @see #editingColumn
0938: */
0939: public void setEditingColumn(int editingColumn) {
0940: this .editingColumn = editingColumn;
0941: }
0942:
0943: /**
0944: * Set the editingRow variable.
0945: *
0946: * @see #editingRow
0947: */
0948: public void setEditingRow(int editingRow) {
0949: this .editingRow = editingRow;
0950: }
0951:
0952: /**
0953: * Return an appropriate editor for the cell specified by this row and
0954: * column. If the TableColumn for this column has a non-null editor, return that.
0955: * If not, find the class of the data in this column (using getColumnClass())
0956: * and return the default editor for this type of data.
0957: *
0958: * @param row the row of the cell to edit, where 0 is the first
0959: * @param col the column of the cell to edit, where 0 is the first
0960: */
0961: public STableCellEditor getCellEditor(int row, int col) {
0962: STableColumnModel columnModel = getColumnModel();
0963: if (columnModel != null) {
0964: STableColumn column = columnModel.getColumn(col);
0965: if (column != null) {
0966: STableCellEditor editor = column.getCellEditor();
0967: if (editor != null)
0968: return editor;
0969: }
0970: }
0971: return getDefaultEditor(getColumnClass(col));
0972: }
0973:
0974: /**
0975: * Prepares the specified editor using the value at the specified cell.
0976: *
0977: * @param editor the TableCellEditor to set up
0978: * @param row the row of the cell to edit, where 0 is the first
0979: * @param col the column of the cell to edit, where 0 is the first
0980: */
0981: protected SComponent prepareEditor(STableCellEditor editor,
0982: int row, int col) {
0983: SComponent component = editor.getTableCellEditorComponent(this ,
0984: getValueAt(row, col), isRowSelected(row), // true?
0985: row, col);
0986: nameEditorComponent(component, row, col);
0987: cellEditorComponent = (component instanceof LowLevelEventListener) ? (LowLevelEventListener) component
0988: : null;
0989:
0990: return component;
0991: }
0992:
0993: /**
0994: * Generates the name (= id) of the editing component so that
0995: * the STable implementation knows to associate the input
0996: * value with the correct data row/columns
0997: *
0998: * Applies the unqique id/name for a component of the rows/column
0999: * to the cell component.
1000: *
1001: * @param component The edit component to rename
1002: * @param row Data row of this edit component
1003: * @param col Data column of this edit component
1004: */
1005: protected void nameEditorComponent(final SComponent component,
1006: final int row, final int col) {
1007: nameBuffer.setLength(0);
1008: nameBuffer.append(this .getName()).append("_e_");
1009: nameBuffer.append(row);
1010: nameBuffer.append('_').append(col);
1011: component.setNameRaw(nameBuffer.toString());
1012: }
1013:
1014: /**
1015: * Discard the editor object and return the real estate it used to
1016: * cell rendering.
1017: */
1018: public void removeEditor() {
1019: STableCellEditor editor = getCellEditor();
1020: if (editor != null) {
1021: editor.removeCellEditorListener(this );
1022: //remove(editorComp);
1023: setCellEditor(null);
1024: int oldEditingColumn = getEditingColumn();
1025: int oldEditingRow = getEditingRow();
1026: setEditingColumn(-1);
1027: setEditingRow(-1);
1028: if (editorComp != null) {
1029: editorComp.setParent(null);
1030: } // end of if ()
1031: editorComp = null;
1032: update(((TableCG) getCG()).getRenderCellUpdate(this ,
1033: oldEditingRow, oldEditingColumn));
1034: }
1035: }
1036:
1037: //
1038: // Implementing the CellEditorListener interface
1039: //
1040:
1041: /**
1042: * Invoked when editing is finished. The changes are saved and the
1043: * editor object is discarded.
1044: *
1045: * @see CellEditorListener
1046: */
1047: public void editingStopped(ChangeEvent e) {
1048: // Take in the new value
1049: STableCellEditor editor = getCellEditor();
1050: if (editor != null) {
1051: Object value = editor.getCellEditorValue();
1052: setValueAt(value, editingRow, editingColumn);
1053: removeEditor();
1054: }
1055: }
1056:
1057: /**
1058: * Invoked when editing is canceled. The editor object is discarded
1059: * and the cell is rendered once again.
1060: *
1061: * @see CellEditorListener
1062: */
1063: public void editingCanceled(ChangeEvent e) {
1064: removeEditor();
1065: }
1066:
1067: /**
1068: * Creates default cell editors for Objects, numbers, and boolean values.
1069: */
1070: protected void createDefaultEditors() {
1071: editors.clear();
1072:
1073: // Objects
1074: setDefaultEditor(Object.class, new SDefaultCellEditor(
1075: new STextField()));
1076: setDefaultEditor(Number.class, new SDefaultCellEditor(
1077: new STextField()));
1078:
1079: // Numbers
1080: //STextField rightAlignedTextField = new STextField();
1081: //rightAlignedTextField.setHorizontalAlignment(STextField.RIGHT);
1082: //setDefaultEditor(Number.class, new SDefaultCellEditor(rightAlignedTextField));
1083:
1084: // Booleans
1085: SCheckBox centeredCheckBox = new SCheckBox();
1086: //centeredCheckBox.setHorizontalAlignment(JCheckBox.CENTER);
1087: setDefaultEditor(Boolean.class, new SDefaultCellEditor(
1088: centeredCheckBox));
1089: }
1090:
1091: /**
1092: * Returns <p>the selection model.</p>
1093: *
1094: * @return <p>the selection model.</p>
1095: */
1096: public SListSelectionModel getSelectionModel() {
1097: return selectionModel;
1098: }
1099:
1100: /**
1101: * Sets the row selection model for this table to <code>model</code>.
1102: *
1103: * @param model the new selection model
1104: * @throws IllegalArgumentException if <code>model</code>
1105: * is <code>null</code>
1106: * @see #getSelectionModel
1107: */
1108: public void setSelectionModel(SListSelectionModel model) {
1109: if (model == null) {
1110: throw new IllegalArgumentException(
1111: "cannot set a null SListSelectionModel");
1112: }
1113:
1114: if (getSelectionModel() != null) {
1115: removeSelectionListener(fwdSelectionEvents);
1116: }
1117:
1118: selectionModel = model;
1119:
1120: addSelectionListener(fwdSelectionEvents);
1121: }
1122:
1123: public int getSelectedRowCount() {
1124: int result = 0;
1125: for (int i = getSelectionModel().getMinSelectionIndex(); i <= getSelectionModel()
1126: .getMaxSelectionIndex(); i++) {
1127: if (getSelectionModel().isSelectedIndex(i))
1128: result++;
1129: }
1130:
1131: return result;
1132: }
1133:
1134: public int getSelectedRow() {
1135: return getSelectionModel().getMinSelectionIndex();
1136: }
1137:
1138: public int[] getSelectedRows() {
1139: int[] result = new int[getSelectedRowCount()];
1140:
1141: int index = 0;
1142: for (int i = getSelectionModel().getMinSelectionIndex(); i <= getSelectionModel()
1143: .getMaxSelectionIndex(); i++) {
1144: if (getSelectionModel().isSelectedIndex(i))
1145: result[index++] = i;
1146: }
1147:
1148: return result;
1149: }
1150:
1151: /**
1152: * Deselects all selected columns and rows.
1153: */
1154: public void clearSelection() {
1155: if (!getSelectionModel().isSelectionEmpty()) {
1156: getSelectionModel().clearSelection();
1157: reload();
1158: }
1159: }
1160:
1161: public boolean isRowSelected(int row) {
1162: return getSelectionModel().isSelectedIndex(row);
1163: }
1164:
1165: /**
1166: * Sets the selection mode. Use one of the following values:
1167: * <UL>
1168: * <LI> {@link #NO_SELECTION}
1169: * <LI> {@link javax.swing.ListSelectionModel#SINGLE_SELECTION} or
1170: * {@link #SINGLE_SELECTION}
1171: * <LI> {@link javax.swing.ListSelectionModel#SINGLE_INTERVAL_SELECTION} or
1172: * {@link #SINGLE_INTERVAL_SELECTION}
1173: * <LI> {@link javax.swing.ListSelectionModel#MULTIPLE_INTERVAL_SELECTION} or
1174: * {@link #MULTIPLE_SELECTION}
1175: * </UL>
1176: */
1177: public void setSelectionMode(int s) {
1178: reloadIfChange(getSelectionModel().getSelectionMode(), s);
1179: getSelectionModel().setSelectionMode(s);
1180: }
1181:
1182: /**
1183: * @return <UL>
1184: * <LI> {@link #NO_SELECTION}
1185: * <LI> {@link javax.swing.ListSelectionModel#SINGLE_SELECTION} or
1186: * {@link #SINGLE_SELECTION}
1187: * <LI> {@link javax.swing.ListSelectionModel#SINGLE_INTERVAL_SELECTION} or
1188: * {@link #SINGLE_INTERVAL_SELECTION}
1189: * <LI> {@link javax.swing.ListSelectionModel#MULTIPLE_INTERVAL_SELECTION} or
1190: * {@link #MULTIPLE_SELECTION}
1191: * </UL>
1192: */
1193: public int getSelectionMode() {
1194: return getSelectionModel().getSelectionMode();
1195: }
1196:
1197: public void addSelectionListener(ListSelectionListener listener) {
1198: getSelectionModel().addListSelectionListener(listener);
1199: }
1200:
1201: public void removeSelectionListener(ListSelectionListener listener) {
1202: getSelectionModel().removeListSelectionListener(listener);
1203: }
1204:
1205: /**
1206: * Adds the specified mouse listener to receive mouse events from
1207: * this component.
1208: * If l is null, no exception is thrown and no action is performed.
1209: *
1210: * @param l the component listener.
1211: * @see org.wings.event.SMouseEvent
1212: * @see org.wings.event.SMouseListener
1213: * @see org.wings.STable#removeMouseListener
1214: */
1215: public final void addMouseListener(SMouseListener l) {
1216: addEventListener(SMouseListener.class, l);
1217: }
1218:
1219: /**
1220: * Removes the specified mouse listener so that it no longer
1221: * receives mouse events from this component. This method performs
1222: * no function, nor does it throw an exception, if the listener
1223: * specified by the argument was not previously added to this component.
1224: * If l is null, no exception is thrown and no action is performed.
1225: *
1226: * @param l the component listener.
1227: * @see org.wings.event.SMouseEvent
1228: * @see org.wings.event.SMouseListener
1229: * @see org.wings.STable#addMouseListener
1230: */
1231: public final void removeMouseListener(SMouseListener l) {
1232: removeEventListener(SMouseListener.class, l);
1233: }
1234:
1235: /**
1236: * Reports a mouse click event.
1237: *
1238: * @param event report this event to all listeners
1239: * @see org.wings.event.SMouseListener
1240: */
1241: protected void fireMouseClickedEvent(SMouseEvent event) {
1242: Object[] listeners = getListenerList();
1243: for (int i = listeners.length - 2; i >= 0; i -= 2) {
1244: if (listeners[i] == SMouseListener.class) {
1245: ((SMouseListener) listeners[i + 1]).mouseClicked(event);
1246: }
1247: }
1248: }
1249:
1250: public void fireIntermediateEvents() {
1251: if (lastReceivedLowLevelEvents == null)
1252: return;
1253:
1254: // delay events...
1255: getSelectionModel().setDelayEvents(true);
1256: getSelectionModel().setValueIsAdjusting(true);
1257:
1258: for (int i = 0; i < lastReceivedLowLevelEvents.length; i++) {
1259: String value = lastReceivedLowLevelEvents[i];
1260: if (value.length() > 1) {
1261:
1262: char modus = value.charAt(0);
1263: value = value.substring(1);
1264: if (value.indexOf(':') == -1)
1265: continue;
1266:
1267: String[] values = value.split(";");
1268: value = values[0];
1269:
1270: try {
1271: SPoint point = new SPoint(value);
1272: int row = rowAtPoint(point);
1273: int col = columnAtPoint(point);
1274:
1275: SMouseEvent event = new SMouseEvent(this , 0, point);
1276: fireMouseClickedEvent(event);
1277: if (event.isConsumed())
1278: continue;
1279:
1280: // editor event
1281: switch (modus) {
1282: case 'e':
1283: editCellAt(row, col, null);
1284: break;
1285: case 't':
1286: boolean shiftKey = Boolean
1287: .parseBoolean(values[1].split("=")[1]);
1288: boolean ctrlKey = Boolean
1289: .parseBoolean(values[2].split("=")[1]);
1290: if (ctrlKey == true
1291: && shiftKey == false
1292: && getSelectionModel().isSelectedIndex(
1293: row))
1294: getSelectionModel()
1295: .removeSelectionInterval(row, row);
1296: else {
1297: if (shiftKey == true) {
1298: getSelectionModel()
1299: .setSelectionInterval(
1300: getSelectionModel()
1301: .getLeadSelectionIndex(),
1302: row);
1303: } else if (ctrlKey == true) {
1304: getSelectionModel()
1305: .addSelectionInterval(row, row);
1306: } else {
1307: getSelectionModel()
1308: .setSelectionInterval(row, row);
1309: }
1310: }
1311: break;
1312: case 's':
1313: getSelectionModel().addSelectionInterval(row,
1314: row);
1315: break;
1316: case 'd':
1317: getSelectionModel().removeSelectionInterval(
1318: row, row);
1319: break;
1320: }
1321: } catch (NumberFormatException ex) {
1322: log
1323: .warn(
1324: "Number format exception while parsing low level events",
1325: ex);
1326: }
1327: }
1328: }
1329: lastReceivedLowLevelEvents = null;
1330:
1331: getSelectionModel().setValueIsAdjusting(false);
1332: getSelectionModel().setDelayEvents(false);
1333:
1334: getSelectionModel().fireDelayedIntermediateEvents();
1335: }
1336:
1337: /**
1338: * Returns the table row for the passed <code>SPoint</code>
1339: * instance received via {@link #addMouseListener(org.wings.event.SMouseListener)}.
1340: * @param point The pointed retuned by the mouse event.
1341: * @return The row index
1342: */
1343: public int rowAtPoint(SPoint point) {
1344: String coordinates = point.getCoordinates();
1345: int colonIndex = coordinates.indexOf(':');
1346: if (colonIndex < 0)
1347: return -1;
1348: return Integer.parseInt(coordinates.substring(0, colonIndex));
1349: }
1350:
1351: /**
1352: * Returns the table column for the passed <code>SPoint</code>
1353: * instance received via {@link #addMouseListener(org.wings.event.SMouseListener)}.
1354: * @param point The pointed retuned by the mouse event.
1355: * @return The column index
1356: * @see #rowAtPoint(SPoint)
1357: */
1358: public int columnAtPoint(SPoint point) {
1359: String coordinates = point.getCoordinates();
1360: int colonIndex = coordinates.indexOf(':');
1361: if (colonIndex < 0)
1362: return -1;
1363: return Integer.parseInt(coordinates.substring(colonIndex + 1));
1364: }
1365:
1366: public void fireFinalEvents() {
1367: super .fireFinalEvents();
1368: // fire selection events...
1369: getSelectionModel().fireDelayedFinalEvents();
1370: }
1371:
1372: /**
1373: * @see LowLevelEventListener#isEpochCheckEnabled()
1374: */
1375: public boolean isEpochCheckEnabled() {
1376: return epochCheckEnabled;
1377: }
1378:
1379: /**
1380: * @see LowLevelEventListener#isEpochCheckEnabled()
1381: */
1382: public void setEpochCheckEnabled(boolean epochCheckEnabled) {
1383: this .epochCheckEnabled = epochCheckEnabled;
1384: }
1385:
1386: public void tableChanged(TableModelEvent e) {
1387: // kill active editors
1388: editingCanceled(null);
1389:
1390: if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
1391: // The whole thing changed
1392: clearSelection();
1393: if (getAutoCreateColumnsFromModel())
1394: createDefaultColumnsFromModel();
1395: } else {
1396: switch (e.getType()) {
1397: case TableModelEvent.INSERT:
1398: if (e.getFirstRow() >= 0)
1399: getSelectionModel().insertIndexInterval(
1400: e.getFirstRow(), e.getLastRow(), true);
1401: break;
1402:
1403: case TableModelEvent.DELETE:
1404: if (e.getFirstRow() >= 0)
1405: getSelectionModel().removeIndexInterval(
1406: e.getFirstRow(), e.getLastRow());
1407: break;
1408: case TableModelEvent.UPDATE:
1409: /* event fire on javax.swing.table.AbstractTableModel.fireTableDataChanged() */
1410: if (e.getLastRow() == Integer.MAX_VALUE)
1411: clearSelection();
1412: break;
1413: }
1414: }
1415:
1416: if (model.getRowCount() != rowCountBackUp) {
1417: rowCountBackUp = model.getRowCount();
1418: fireViewportChanged(false);
1419: }
1420: if (columnModel.getColumnCount() != columnCountBackUp) {
1421: columnCountBackUp = columnModel.getColumnCount();
1422: fireViewportChanged(true);
1423: }
1424:
1425: if (e != null && e.getFirstRow() == e.getLastRow()
1426: && e.getFirstRow() != TableModelEvent.HEADER_ROW
1427: && e.getColumn() != TableModelEvent.ALL_COLUMNS
1428: && e.getType() == TableModelEvent.UPDATE) {
1429: if (isUpdatePossible()
1430: && STable.class.isAssignableFrom(getClass()))
1431: update(((TableCG) getCG()).getRenderCellUpdate(this , e
1432: .getFirstRow(), e.getColumn()));
1433: else
1434: reload();
1435: } else {
1436: reload();
1437: }
1438: }
1439:
1440: /**
1441: * Return the background color.
1442: *
1443: * @return the background color
1444: */
1445: public Color getSelectionBackground() {
1446: return dynamicStyles == null
1447: || dynamicStyles.get(SELECTOR_SELECTED) == null ? null
1448: : CSSStyleSheet
1449: .getBackground((CSSAttributeSet) dynamicStyles
1450: .get(SELECTOR_SELECTED));
1451: }
1452:
1453: /**
1454: * Set the foreground color.
1455: *
1456: * @param color the new foreground color
1457: */
1458: public void setSelectionBackground(Color color) {
1459: setAttribute(SELECTOR_SELECTED, CSSProperty.BACKGROUND_COLOR,
1460: CSSStyleSheet.getAttribute(color));
1461: }
1462:
1463: /**
1464: * Return the foreground color.
1465: *
1466: * @return the foreground color
1467: */
1468: public Color getSelectionForeground() {
1469: return dynamicStyles == null
1470: || dynamicStyles.get(SELECTOR_SELECTED) == null ? null
1471: : CSSStyleSheet
1472: .getForeground((CSSAttributeSet) dynamicStyles
1473: .get(SELECTOR_SELECTED));
1474: }
1475:
1476: /**
1477: * Set the foreground color.
1478: *
1479: * @param color the new foreground color
1480: */
1481: public void setSelectionForeground(Color color) {
1482: setAttribute(SELECTOR_SELECTED, CSSProperty.COLOR,
1483: CSSStyleSheet.getAttribute(color));
1484: }
1485:
1486: /**
1487: * Set the font.
1488: *
1489: * @param font the new font
1490: */
1491: public void setSelectionFont(SFont font) {
1492: setAttributes(SELECTOR_SELECTED, CSSStyleSheet
1493: .getAttributes(font));
1494: }
1495:
1496: /**
1497: * Return the font.
1498: *
1499: * @return the font
1500: */
1501: public SFont getSelectionFont() {
1502: return dynamicStyles == null
1503: || dynamicStyles.get(SELECTOR_SELECTED) == null ? null
1504: : CSSStyleSheet.getFont((CSSAttributeSet) dynamicStyles
1505: .get(SELECTOR_SELECTED));
1506: }
1507:
1508: /**
1509: * Return the background color.
1510: *
1511: * @return the background color
1512: */
1513: public Color getHeaderBackground() {
1514: return dynamicStyles == null
1515: || dynamicStyles.get(SELECTOR_HEADER) == null ? null
1516: : CSSStyleSheet
1517: .getBackground((CSSAttributeSet) dynamicStyles
1518: .get(SELECTOR_HEADER));
1519: }
1520:
1521: /**
1522: * Set the foreground color.
1523: *
1524: * @param color the new foreground color
1525: */
1526: public void setHeaderBackground(Color color) {
1527: setAttribute(SELECTOR_HEADER, CSSProperty.BACKGROUND_COLOR,
1528: CSSStyleSheet.getAttribute(color));
1529: }
1530:
1531: /**
1532: * Return the foreground color.
1533: *
1534: * @return the foreground color
1535: */
1536: public Color getHeaderForeground() {
1537: return dynamicStyles == null
1538: || dynamicStyles.get(SELECTOR_HEADER) == null ? null
1539: : CSSStyleSheet
1540: .getForeground((CSSAttributeSet) dynamicStyles
1541: .get(SELECTOR_HEADER));
1542: }
1543:
1544: /**
1545: * Set the foreground color.
1546: *
1547: * @param color the new foreground color
1548: */
1549: public void setHeaderForeground(Color color) {
1550: setAttribute(SELECTOR_HEADER, CSSProperty.COLOR, CSSStyleSheet
1551: .getAttribute(color));
1552: }
1553:
1554: /**
1555: * Set the font.
1556: *
1557: * @param font the new font
1558: */
1559: public void setHeaderFont(SFont font) {
1560: setAttributes(SELECTOR_HEADER, CSSStyleSheet
1561: .getAttributes(font));
1562: }
1563:
1564: /**
1565: * Return the font.
1566: *
1567: * @return the font
1568: */
1569: public SFont getHeaderFont() {
1570: return dynamicStyles == null
1571: || dynamicStyles.get(SELECTOR_HEADER) == null ? null
1572: : CSSStyleSheet.getFont((CSSAttributeSet) dynamicStyles
1573: .get(SELECTOR_HEADER));
1574: }
1575:
1576: /**
1577: * Sets <p>Determines whether the header is visible or not.</p><p>By
1578: * default the header is visible.</p> <p><em>CAVEAT:</em>The
1579: * header is not (yet) implemented like in Swing. But maybe
1580: * someday. So you can disable it if you like.</p>
1581: *
1582: * @param hv <p>Determines whether the header is visible or not.</p><p>By
1583: */
1584: public void setHeaderVisible(boolean hv) {
1585: boolean oldHeaderVisible = headerVisible;
1586: headerVisible = hv;
1587: if (oldHeaderVisible != headerVisible) {
1588: reload();
1589: }
1590: }
1591:
1592: /**
1593: * Returns <p>Determines whether the header is visible or not.</p><p>By
1594: * default the header is visible.</p> <p><em>CAVEAT:</em>The
1595: * header is not (yet) implemented like in Swing. But maybe
1596: * someday. So you can disable it if you like.</p>
1597: *
1598: * @return <p>Determines whether the header is visible or not.</p><p>By
1599: */
1600: public boolean isHeaderVisible() {
1601: return headerVisible;
1602: }
1603:
1604: public void setShowGrid(boolean b) {
1605: setShowHorizontalLines(b);
1606: setShowVerticalLines(b);
1607: }
1608:
1609: /**
1610: * Sets <p>Determines if horizontal lines in the table should be
1611: * painted.</p><p>This is off by default.</p>
1612: *
1613: * @param b <p>Determines if horizontal lines in the table should be
1614: */
1615: public void setShowHorizontalLines(boolean b) {
1616: boolean oldShowHorizontalLines = showHorizontalLines;
1617: showHorizontalLines = b;
1618: if (showHorizontalLines != oldShowHorizontalLines) {
1619: reload();
1620: }
1621: }
1622:
1623: /**
1624: * Returns <p>Determines if horizontal lines in the table should be
1625: * painted.</p><p>This is off by default.</p>
1626: *
1627: * @return <p>Determines if horizontal lines in the table should be
1628: */
1629: public boolean getShowHorizontalLines() {
1630: return showHorizontalLines;
1631: }
1632:
1633: /**
1634: * Sets <p>Determines if vertical lines in the table should be
1635: * painted.</p><p>This is off by default.</p>
1636: *
1637: * @param b <p>Determines if vertical lines in the table should be
1638: */
1639: public void setShowVerticalLines(boolean b) {
1640: boolean oldShowVerticalLines = showVerticalLines;
1641: showVerticalLines = b;
1642: if (showVerticalLines != oldShowVerticalLines) {
1643: reload();
1644: }
1645: }
1646:
1647: /**
1648: * Returns <p>Determines if vertical lines in the table should be
1649: * painted.</p><p>This is off by default.</p>
1650: *
1651: * @return <p>Determines if vertical lines in the table should be
1652: */
1653: public boolean getShowVerticalLines() {
1654: return showVerticalLines;
1655: }
1656:
1657: /*
1658: * Implementiert das cellspacing Attribut des HTML Tables. Da dieses
1659: * nur eindimensional ist, wird nur der width Wert der Dimension in
1660: * den HTML Code uebernommen.
1661: */
1662: public void setIntercellSpacing(SDimension d) {
1663: SDimension oldIntercellSpacing = intercellSpacing;
1664: intercellSpacing = d;
1665: if ((intercellSpacing == null && oldIntercellSpacing != null)
1666: || intercellSpacing != null
1667: && !intercellSpacing.equals(oldIntercellSpacing))
1668: reload();
1669: }
1670:
1671: public SDimension getIntercellSpacing() {
1672: return intercellSpacing;
1673: }
1674:
1675: /*
1676: * Implementiert das cellpadding Attribut des HTML Tables. Da dieses
1677: * nur eindimensional ist, wird nur der width Wert der Dimension in
1678: * den HTML Code uebernommen.
1679: */
1680:
1681: public void setIntercellPadding(SDimension d) {
1682: SDimension oldIntercellPadding = intercellPadding;
1683: intercellPadding = d;
1684: if ((intercellPadding == null && oldIntercellPadding != null)
1685: || intercellPadding != null
1686: && !intercellPadding.equals(oldIntercellPadding))
1687: reload();
1688: }
1689:
1690: public SDimension getIntercellPadding() {
1691: return intercellPadding;
1692: }
1693:
1694: /**
1695: * wingS internal method used to create specific HTTP request parameter names.
1696: */
1697: public String getEditParameter(int row, int col) {
1698: return "e" + row + ":" + col;
1699: }
1700:
1701: /**
1702: * wingS internal method used to create specific HTTP request parameter names.
1703: */
1704: public String getToggleSelectionParameter(int row, int col) {
1705: return "t"
1706: + row
1707: + ":"
1708: + col
1709: + ";shiftKey='+event.shiftKey+';ctrlKey='+event.ctrlKey+'";
1710: }
1711:
1712: /**
1713: * wingS internal method used to create specific HTTP request parameter names.
1714: */
1715: public String getSelectionParameter(int row, int col) {
1716: return "s" + row + ":" + col;
1717: }
1718:
1719: /**
1720: * wingS internal method used to create specific HTTP request parameter names.
1721: */
1722: public String getDeselectionParameter(int row, int col) {
1723: return "d" + row + ":" + col;
1724: }
1725:
1726: /**
1727: * The size of the component in respect to scrollable units.
1728: */
1729: public Rectangle getScrollableViewportSize() {
1730: return new Rectangle(0, 0, getVisibleColumnCount(),
1731: getRowCount());
1732: }
1733:
1734: /**
1735: * Returns the actual visible part of a scrollable.
1736: */
1737: public Rectangle getViewportSize() {
1738: return viewport;
1739: }
1740:
1741: /**
1742: * Sets the actual visible part of a scrollable.
1743: */
1744: public void setViewportSize(Rectangle newViewport) {
1745: Rectangle oldViewport = viewport;
1746: viewport = newViewport;
1747:
1748: if (isDifferent(oldViewport, newViewport)) {
1749: if (oldViewport == null || newViewport == null) {
1750: fireViewportChanged(true);
1751: fireViewportChanged(false);
1752: } else {
1753: if (newViewport.x != oldViewport.x
1754: || newViewport.width != oldViewport.width) {
1755: fireViewportChanged(true);
1756: }
1757: if (newViewport.y != oldViewport.y
1758: || newViewport.height != oldViewport.height) {
1759: fireViewportChanged(false);
1760: }
1761: }
1762: update(((TableCG) getCG()).getTableScrollUpdate(this ,
1763: newViewport, oldViewport));
1764: }
1765: }
1766:
1767: /**
1768: * Adds the given <code>SViewportChangeListener</code> to the scrollable.
1769: *
1770: * @param l the listener to be added
1771: */
1772: public void addViewportChangeListener(SViewportChangeListener l) {
1773: addEventListener(SViewportChangeListener.class, l);
1774: }
1775:
1776: /**
1777: * Removes the given <code>SViewportChangeListener</code> from the scrollable.
1778: *
1779: * @param l the listener to be removed
1780: */
1781: public void removeViewportChangeListener(SViewportChangeListener l) {
1782: removeEventListener(SViewportChangeListener.class, l);
1783: }
1784:
1785: /**
1786: * Notifies all listeners that have registered interest for notification
1787: * on changes to this scrollable's viewport in the specified direction.
1788: *
1789: * @see javax.swing.event.EventListenerList
1790: */
1791: protected void fireViewportChanged(boolean horizontal) {
1792: Object[] listeners = getListenerList();
1793: for (int i = listeners.length - 2; i >= 0; i -= 2) {
1794: if (listeners[i] == SViewportChangeListener.class) {
1795: SViewportChangeEvent event = new SViewportChangeEvent(
1796: this , horizontal);
1797: ((SViewportChangeListener) listeners[i + 1])
1798: .viewportChanged(event);
1799: }
1800: }
1801: }
1802:
1803: public void setSelectedRow(int selectedIndex) {
1804: getSelectionModel().setSelectionInterval(selectedIndex,
1805: selectedIndex);
1806: }
1807:
1808: /**
1809: * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
1810: * This method calls <code>createDefaultColumnsFromModel</code> if
1811: * <code>autoCreateColumnsFromModel</code> changes from false to true.
1812: *
1813: * @param autoCreateColumnsFromModel true if <code>JTable</code> should automatically create columns
1814: * @see #getAutoCreateColumnsFromModel
1815: * @see #createDefaultColumnsFromModel
1816: */
1817: public void setAutoCreateColumnsFromModel(
1818: boolean autoCreateColumnsFromModel) {
1819: if (this .autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
1820: this .autoCreateColumnsFromModel = autoCreateColumnsFromModel;
1821: if (autoCreateColumnsFromModel) {
1822: createDefaultColumnsFromModel();
1823: }
1824: }
1825: }
1826:
1827: /**
1828: * Determines whether the table will create default columns from the model.
1829: * If true, <code>setModel</code> will clear any existing columns and
1830: * create new columns from the new model. Also, if the event in
1831: * the <code>tableChanged</code> notification specifies that the
1832: * entire table changed, then the columns will be rebuilt.
1833: * The default is true.
1834: *
1835: * @return the autoCreateColumnsFromModel of the table
1836: * @see #setAutoCreateColumnsFromModel
1837: * @see #createDefaultColumnsFromModel
1838: */
1839: public boolean getAutoCreateColumnsFromModel() {
1840: return autoCreateColumnsFromModel;
1841: }
1842:
1843: /**
1844: * Returns a <code>STableColumnModel</code> that contains information
1845: * about all columns of this table.
1846: *
1847: * @return the object that provides the column state of the table
1848: * @see #setColumnModel
1849: */
1850: public STableColumnModel getColumnModel() {
1851: return columnModel;
1852: }
1853:
1854: /**
1855: * Sets the model holding information about the columns for this table.
1856: *
1857: * @param newColumnModel the new data source for this table
1858: * @see #getColumnModel
1859: */
1860: public void setColumnModel(STableColumnModel newColumnModel) {
1861: if (newColumnModel == null)
1862: throw new IllegalArgumentException(
1863: "Column model must not be null");
1864:
1865: if (columnModel != newColumnModel) {
1866: if (tableColumnModelListener == null)
1867: tableColumnModelListener = createTableColumnModelListener();
1868:
1869: if (columnModel != null)
1870: columnModel
1871: .removeColumnModelListener(tableColumnModelListener);
1872: columnModel = newColumnModel;
1873: columnModel
1874: .addColumnModelListener(tableColumnModelListener);
1875:
1876: reload();
1877: }
1878: }
1879:
1880: /**
1881: * Creates the default columns of the table from the table model.
1882: */
1883: public void createDefaultColumnsFromModel() {
1884: TableModel tm = getModel();
1885:
1886: if (tm != null) {
1887: STableColumnModel columnModel = getColumnModel();
1888: while (columnModel.getColumnCount() > 0)
1889: columnModel.removeColumn(columnModel.getColumn(0));
1890:
1891: for (int i = 0; i < tm.getColumnCount(); i++) {
1892: STableColumn column = new STableColumn(i);
1893: String columnName = tm.getColumnName(i);
1894: column.setHeaderValue(columnName);
1895: this .columnModel.addColumn(column);
1896: }
1897: }
1898: }
1899:
1900: /**
1901: * Returns the default column model object, which is
1902: * a <code>SDefaultTableColumnModel</code>.
1903: * A subclass can override this method to return a different column model object.
1904: *
1905: * @return the default column model object
1906: */
1907: protected STableColumnModel createDefaultColumnModel() {
1908: return new SDefaultTableColumnModel();
1909: }
1910:
1911: /**
1912: * Returns a default table model object.
1913: * Subclasses can override this method to return a different table model objects
1914: *
1915: * @return the default table model object
1916: * @see javax.swing.table.DefaultTableModel
1917: */
1918: protected TableModel createDefaultDataModel() {
1919: return new DefaultTableModel();
1920: }
1921:
1922: /**
1923: * Creates an instance of TableColumnModelHandler.
1924: */
1925: protected TableColumnModelHandler createTableColumnModelListener() {
1926: return new TableColumnModelHandler();
1927: }
1928:
1929: /**
1930: * Handler that listens to the table's column model.
1931: */
1932: protected class TableColumnModelHandler implements
1933: STableColumnModelListener {
1934:
1935: public void columnAdded(STableColumnModelEvent e) {
1936: removeEditor();
1937: fireViewportChanged(true);
1938: reload();
1939: }
1940:
1941: public void columnHidden(ChangeEvent e) {
1942: removeEditor();
1943: fireViewportChanged(true);
1944: reload();
1945: }
1946:
1947: public void columnMarginChanged(ChangeEvent e) {
1948: reload();
1949: }
1950:
1951: public void columnMoved(STableColumnModelEvent e) {
1952: removeEditor();
1953: reload();
1954: }
1955:
1956: public void columnRemoved(STableColumnModelEvent e) {
1957: removeEditor();
1958: fireViewportChanged(true);
1959: reload();
1960: }
1961:
1962: public void columnShown(ChangeEvent e) {
1963: removeEditor();
1964: fireViewportChanged(true);
1965: reload();
1966: }
1967: }
1968: }
|