001: package net.xoetrope.swing;
002:
003: import java.awt.Dimension;
004: import java.awt.ItemSelectable;
005: import java.awt.event.ItemListener;
006:
007: import net.xoetrope.xui.XAttributedComponent;
008: import net.xoetrope.xui.XModelHolder;
009: import net.xoetrope.xui.data.XModel;
010: import net.xoetrope.xui.style.XStyleComponent;
011: import java.awt.Container;
012: import javax.swing.JTable;
013: import javax.swing.table.TableModel;
014: import javax.swing.event.TableModelListener;
015: import java.util.Vector;
016: import net.xoetrope.xui.XProjectManager;
017: import net.xoetrope.xui.style.XStyle;
018: import javax.swing.table.JTableHeader;
019: import javax.swing.event.ListSelectionListener;
020: import javax.swing.event.ListSelectionEvent;
021: import net.xoetrope.xui.data.XRowSelector;
022: import javax.swing.ListSelectionModel;
023: import net.xoetrope.xui.events.XHandlerInvoker;
024: import net.xoetrope.xui.events.XListenerHelper;
025: import net.xoetrope.xui.XPage;
026: import net.xoetrope.xui.style.XStyleManager;
027: import javax.swing.event.TableModelEvent;
028: import net.xoetrope.xui.data.XBaseModel;
029:
030: /**
031: * <p>Provides a wrapper for the JTable and offer some compatibility with the
032: * AWT version of the XTable.</p>
033: * <p>Copyright (c) Xoetrope Ltd., 1998-2004<br>
034: * License: see license.txt
035: * $Revision: 1.5 $
036: */
037: public class XTable2 extends JTable implements XAttributedComponent,
038: XModelHolder, XStyleComponent, XRowSelector, XListenerHelper {
039: private XModel model;
040: private boolean updateModelSelection = false;
041: private XHandlerInvoker invoker;
042: private int oldRowSelection = -1;
043:
044: public XTable2() {
045: super ();
046:
047: setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
048: }
049:
050: /**
051: * Force the table to update itself
052: */
053: public void updateTable() {
054: tableChanged(new TableModelEvent(dataModel));
055: }
056:
057: /**
058: * Add an event handler response method to a component such that the page's
059: * response method is invoked when the event occurs
060: * @param page the page containing the method
061: * @param handlerType the type of event handler
062: * @param methodName the method to invoke
063: * @throws NoSuchMethodException
064: */
065: public void addHandler(XPage page, String handlerType,
066: String methodName) throws NoSuchMethodException {
067: invoker = new XHandlerInvoker(page, this , methodName);
068: }
069:
070: /**
071: * The row selection has changes, update the model if required.
072: * @param le the list selection event
073: */
074: public void valueChanged(ListSelectionEvent le) {
075: super .valueChanged(le);
076:
077: if (updateModelSelection && (model instanceof XRowSelector)) {
078: int selRowIdx = getSelectedRow();
079: if (selRowIdx >= 0) {
080: ((XRowSelector) model).setSelectedRow(selRowIdx);
081: if ((oldRowSelection != selRowIdx) && (invoker != null))
082: invoker.invoke();
083: oldRowSelection = selRowIdx;
084: }
085: }
086: }
087:
088: /**
089: * Set the XModel which we will be generating the table from
090: * @param xmodel The XModel of data
091: */
092: public void setModel(XModel xmodel) {
093: model = xmodel;
094: if (model != null) {
095: model.get();
096: setModel(new XTableModel(model));
097: }
098: }
099:
100: /**
101: * Get the underlying model.
102: * @return the model
103: */
104: public XModel getXModel() {
105: return model;
106: }
107:
108: /**
109: * Set the general style of the XTable
110: * @param style XStyle
111: */
112: public void setStyle(String style) {
113: XStyleManager styleMgr = XProjectManager.getStyleManager();
114: XStyle xstyle = styleMgr.getStyle(style);
115: setForeground(xstyle.getStyleAsColor(XStyle.COLOR_FORE));
116: setBackground(xstyle.getStyleAsColor(XStyle.COLOR_BACK));
117: setFont(styleMgr.getFont(xstyle));
118: }
119:
120: /**
121: * Set the style of the header data
122: * @param style XStyle
123: */
124: public void setHeaderStyle(String style) {
125: XStyleManager styleMgr = XProjectManager.getStyleManager();
126: XStyle xstyle = styleMgr.getStyle(style);
127: JTableHeader th = getTableHeader();
128: th.setForeground(xstyle.getStyleAsColor(XStyle.COLOR_FORE));
129: th.setBackground(xstyle.getStyleAsColor(XStyle.COLOR_BACK));
130: th.setFont(styleMgr.getFont(xstyle));
131: }
132:
133: /**
134: * Set the style of the selected row
135: * @param style XStyle
136: */
137: public void setSelectedStyle(String style) {
138: XStyle xstyle = XProjectManager.getStyleManager().getStyle(
139: style);
140: setSelectionForeground(xstyle
141: .getStyleAsColor(XStyle.COLOR_FORE));
142: setSelectionBackground(xstyle
143: .getStyleAsColor(XStyle.COLOR_BACK));
144: }
145:
146: /**
147: * Set the style of the border
148: * @param style XStyle
149: */
150: public void setBorderStyle(String style) {
151: // content.setBorderStyle( style );
152: }
153:
154: /**
155: * Check the if the table is interactive
156: * @return true if the table supports user interaction
157: */
158: public boolean isInteractiveTable() {
159: // return content.isInteractiveTable();
160: return false;
161: }
162:
163: /**
164: * Set the user interaction state
165: * @param state true for an user interactive table.
166: */
167: public void setInteractiveTable(boolean state) {
168: // content.setInteractiveTable( state );
169: }
170:
171: /**
172: * Sets the indexof the selected row
173: * @param idx the new selected row
174: */
175: public void setSelectedRow(int idx) {
176: setRowSelectionInterval(idx, idx);
177: }
178:
179: /**
180: * Move to the first row
181: */
182: public void first() {
183: if (getRowCount() > 0)
184: setSelectedRow(0);
185: }
186:
187: /**
188: * Move to the previous row
189: */
190: public void prev() {
191: setSelectedRow(getSelectedRow() - 1);
192: }
193:
194: /**
195: * Move to the next row
196: */
197: public void next() {
198: setSelectedRow(getSelectedRow() + 1);
199: }
200:
201: /**
202: * Move to the last row
203: */
204: public void last() {
205: setSelectedRow(model.getNumChildren() - 1);
206: }
207:
208: /**
209: * Tie the model selection to this table's selection
210: * @param doUpdate true to tie the selections together, false to ignore
211: */
212: public void setUpdateModelSelection(boolean doUpdate) {
213: updateModelSelection = doUpdate;
214: }
215:
216: /**
217: * Set the table column width;
218: * @param fieldIdx the field index
219: * @param w the new column width
220: */
221: public void setColWidth(int fieldIdx, int w) {
222: // content.setColWidth( fieldIdx, w );
223: }
224:
225: /**
226: * Set one or more attributes of the component. Currently this handles the
227: * attributes
228: * <OL>
229: * <LI>headingStyle, value=the table header style</LI>
230: * <LI>selectionStyle, value=the selected row style</LI>
231: * <LI>interactive, value=true|false</LI>
232: * <LI>updateModel, value=true|false update the underlying model selection (the selected row)</LI>
233: * </OL>
234: * @param attribName the attribute name
235: * @param attribValue the attribute value
236: */
237: public void setAttribute(String attribName, String attribValue) {
238: if (attribName.compareTo("headingStyle") == 0)
239: setHeaderStyle(attribValue);
240: else if (attribName.compareTo("selectionStyle") == 0)
241: setSelectedStyle(attribValue);
242: else if (attribName.compareTo("borderStyle") == 0)
243: setBorderStyle(attribValue);
244: else if (attribName.compareTo("interactive") == 0)
245: setInteractiveTable(attribValue.compareTo("true") == 0);
246: else if (attribName.compareTo("updateModel") == 0)
247: setUpdateModelSelection(attribValue.compareTo("true") == 0);
248: // super.setAttribute( attribName, attribValue );
249: }
250:
251: /**
252: * Gets a field value object from the currently selected row
253: * @param fieldIdx the field offset
254: * @return the value
255: */
256: public Object getValue(int fieldIdx) {
257: int row = getSelectedRow();
258: return getValue(row, fieldIdx);
259: }
260:
261: /**
262: * Gets a field value object from the specified row
263: * @param rowIdx the row offset
264: * @param fieldIdx the field offset
265: * @return the value
266: */
267: public Object getValue(int rowIdx, int fieldIdx) {
268: XModel rowModel = model
269: .get(rowIdx + 0/*content.getFirstRow()*/);
270: Object fieldModel = rowModel.get(fieldIdx);
271: if (fieldModel instanceof XModel)
272: return ((XModel) fieldModel).get();
273: return fieldModel;
274: }
275:
276: /**
277: * Gets a field value as a string from the currently selected row
278: * @param fieldIdx the field offset
279: * @return the value
280: */
281: public String getFieldValue(int fieldIdx) {
282: return (String) getValue(fieldIdx);
283:
284: }
285:
286: /**
287: * Gets a field value as a string from the specified row
288: * @param rowIdx the row offset
289: * @param fieldIdx the field offset
290: * @return the value
291: */
292: public String getFieldValue(int rowIdx, int fieldIdx) {
293: return (String) getValue(rowIdx, fieldIdx);
294: }
295: }
296:
297: class XTableModel implements TableModel {
298: XModel model;
299: Vector listeners;
300: boolean hasHeaderRow;
301:
302: public XTableModel(XModel newModel) {
303: model = newModel;
304: listeners = new Vector();
305: hasHeaderRow = false;
306: }
307:
308: /**
309: * Returns the number of rows in the model. A
310: * <code>JTable</code> uses this method to determine how many rows it
311: * should display. This method should be quick, as it
312: * is called frequently during rendering.
313: *
314: * @return the number of rows in the model
315: * @see #getColumnCount
316: */
317: public int getRowCount() {
318: if (hasHeaderRow)
319: return model.getNumChildren() - 1;
320: return model.getNumChildren();
321: }
322:
323: /**
324: * Returns the number of columns in the model. A
325: * <code>JTable</code> uses this method to determine how many columns it
326: * should create and display by default.
327: *
328: * @return the number of columns in the model
329: * @see #getRowCount
330: */
331: public int getColumnCount() {
332: if (model.getNumChildren() > 0) {
333: if (model instanceof XBaseModel) {
334: XBaseModel row0 = (XBaseModel) ((XBaseModel) model)
335: .get(0);
336: if (row0.getTagName().equals("th")) {
337: hasHeaderRow = true;
338: return row0.getNumChildren();
339: }
340: }
341: }
342: return model.getNumAttributes();
343: }
344:
345: /**
346: * Returns the name of the column at <code>columnIndex</code>. This is used
347: * to initialize the table's column header name. Note: this name does
348: * not need to be unique; two columns in a table can have the same name.
349: *
350: * @param columnIndex the index of the column
351: * @return the name of the column
352: */
353: public String getColumnName(int columnIndex) {
354: if (hasHeaderRow) {
355: XBaseModel row0 = (XBaseModel) ((XBaseModel) model).get(0);
356: return row0.get(columnIndex).getAttribValueAsString(
357: XBaseModel.VALUE_ATTRIBUTE);
358: }
359:
360: return model.getAttribName(columnIndex);
361: }
362:
363: /**
364: * Returns the most specific superclass for all the cell values
365: * in the column. This is used by the <code>JTable</code> to set up a
366: * default renderer and editor for the column.
367: *
368: * @param columnIndex the index of the column
369: * @return the common ancestor class of the object values in the model.
370: */
371: public Class getColumnClass(int columnIndex) {
372: return String.class;
373: }
374:
375: /**
376: * Returns true if the cell at <code>rowIndex</code> and
377: * <code>columnIndex</code>
378: * is editable. Otherwise, <code>setValueAt</code> on the cell will not
379: * change the value of that cell.
380: *
381: * @param rowIndex the row whose value to be queried
382: * @param columnIndex the column whose value to be queried
383: * @return true if the cell is editable
384: * @see #setValueAt
385: */
386: public boolean isCellEditable(int rowIndex, int columnIndex) {
387: return false;
388: }
389:
390: /**
391: * Returns the value for the cell at <code>columnIndex</code> and
392: * <code>rowIndex</code>.
393: *
394: * @param rowIndex the row whose value is to be queried
395: * @param columnIndex the column whose value is to be queried
396: * @return the value Object at the specified cell
397: */
398: public Object getValueAt(int rowIndex, int columnIndex) {
399: return model.get(rowIndex + (hasHeaderRow ? 1 : 0)).get(
400: columnIndex).get();
401: }
402:
403: /**
404: * Sets the value in the cell at <code>columnIndex</code> and
405: * <code>rowIndex</code> to <code>aValue</code>.
406: *
407: * @param aValue the new value
408: * @param rowIndex the row whose value is to be changed
409: * @param columnIndex the column whose value is to be changed
410: * @see #getValueAt
411: * @see #isCellEditable
412: */
413: public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
414:
415: }
416:
417: /**
418: * Adds a listener to the list that is notified each time a change
419: * to the data model occurs.
420: *
421: * @param l the TableModelListener
422: */
423: public void addTableModelListener(TableModelListener l) {
424: listeners.add(l);
425: }
426:
427: /**
428: * Removes a listener from the list that is notified each time a
429: * change to the data model occurs.
430: *
431: * @param l the TableModelListener
432: */
433: public void removeTableModelListener(TableModelListener l) {
434: listeners.remove(l);
435: }
436: }
|