001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings;
014:
015: import java.awt.event.ActionEvent;
016: import java.awt.event.ActionListener;
017: import java.io.Serializable;
018: import java.util.EventObject;
019: import java.util.Arrays;
020:
021: import javax.swing.event.CellEditorListener;
022: import javax.swing.event.ChangeEvent;
023: import javax.swing.event.EventListenerList;
024:
025: import org.wings.resource.ResourceManager;
026: import org.wings.table.STableCellEditor;
027:
028: /**
029: * Default table cell editor.
030: *
031: * @author <a href="mailto:engels@mercatis.de">Holger Engels</a>
032: */
033: public class SDefaultCellEditor implements STableCellEditor {
034: /**
035: *
036: */
037: private static final long serialVersionUID = 1L;
038:
039: /**
040: * The default ok button icon.
041: */
042: private static final SIcon OK_BUTTON_ICON = (SIcon) ResourceManager
043: .getObject("SDefaultCellEditor.okIcon", SIcon.class);
044:
045: /**
046: * The default cancel button icon.
047: */
048: private static final SIcon CANCEL_BUTTON_ICON = (SIcon) ResourceManager
049: .getObject("SDefaultCellEditor.cancelIcon", SIcon.class);
050:
051: /**
052: * Label for displaying (error)-messages. It is unvisible, until a message
053: * is set.
054: */
055: protected final SLabel messageLabel;
056:
057: /**
058: * Panel for edit fields.
059: */
060: protected final EditorPanel editorPanel;
061:
062: /**
063: * If this button is pressed, editing is tried to stop. If input validation
064: * found no error, editing is stopped, else an error message is displayed
065: */
066: protected final SClickable ok;
067:
068: /**
069: * If this button is pressed, editing is canceled.
070: */
071: protected final SClickable cancel;
072:
073: /**
074: * Store here the CellEditorListener
075: */
076: protected final EventListenerList listenerList;
077:
078: /**
079: * Fast edit support is editing with reduced interaction. E.g. a boolean
080: * value can only have to states, true or false. So if editing is started,
081: * the editor just flips the state and fires editing stopped.
082: */
083: private boolean fastEditSupport = true;
084:
085: protected EditorDelegate delegate;
086:
087: protected SComponent editorComponent;
088:
089: /**
090: * Initialize the DefaultCellEditor with an editor component (like an text
091: * field for instance). After calling this constructor, the
092: * {@link EditorDelegate}, that links the CellEditor and the
093: * editorComponent has to be passed to the delegate instance variable.
094: *
095: * @param editorComponent the component used
096: * @param initializeButtons flag to indicate if the button texts and icons
097: * should be initialized.
098: */
099: protected SDefaultCellEditor(SComponent editorComponent,
100: boolean initializeButtons) {
101: this .messageLabel = new SLabel();
102: this .editorPanel = new EditorPanel();
103: this .ok = new SClickable();
104: this .cancel = new SClickable();
105: this .listenerList = new EventListenerList();
106: this .editorComponent = editorComponent;
107:
108: editorPanel.add(messageLabel);
109: editorPanel.add(editorComponent);
110: if (initializeButtons) {
111: initButtons();
112: }
113: }
114:
115: /**
116: * Constructs a DefaultCellEditor that uses a text field.
117: *
118: * @param x a STextField object ...
119: */
120: public SDefaultCellEditor(STextField x) {
121: this (x, true);
122: this .delegate = new EditorDelegate() {
123: public void setValue(Object v) {
124: super .setValue(v);
125: ((STextField) editorComponent).setText(v != null ? v
126: .toString() : null);
127: }
128:
129: public Object getCellEditorValue() {
130: String text = ((STextField) editorComponent).getText();
131: return "".equals(text) ? null : text;
132: }
133:
134: public boolean shouldSelectCell(EventObject anEvent) {
135: return true;
136: }
137: };
138: }
139:
140: /**
141: * Constructs a DefaultCellEditor object that uses a check box.
142: *
143: * @param x a SCheckBox object ...
144: */
145: public SDefaultCellEditor(SCheckBox x) {
146: this (x, true);
147: this .delegate = new EditorDelegate() {
148: public void setValue(Object v) {
149: // Try my best to do the right thing with v
150: boolean bool;
151: if (v instanceof Boolean) {
152: bool = ((Boolean) v).booleanValue();
153: } else if (v instanceof String) {
154: Boolean b = Boolean.valueOf((String) v);
155: bool = b.booleanValue();
156: } else {
157: bool = false;
158: }
159:
160: if (fastEditSupport) {
161: ((SCheckBox) editorComponent).setSelected(!bool);
162: SDefaultCellEditor.this .stopCellEditing();
163: } else {
164: ((SCheckBox) editorComponent).setSelected(bool);
165: }
166: }
167:
168: public Object getCellEditorValue() {
169: return Boolean.valueOf(((SCheckBox) editorComponent)
170: .isSelected());
171: }
172:
173: public boolean shouldSelectCell(EventObject anEvent) {
174: return false;
175: }
176: };
177: }
178:
179: /**
180: * Intializes the buttons with default icons, tooltip text and listener.
181: */
182: protected void initButtons() {
183: ok.setEvent("ok");
184: ok.setIcon(OK_BUTTON_ICON);
185: ok.setToolTipText("ok");
186: ok.setEventTarget(editorPanel);
187:
188: cancel.setEvent("cancel");
189: cancel.setIcon(CANCEL_BUTTON_ICON);
190: cancel.setToolTipText("cancel");
191: cancel.setEventTarget(editorPanel);
192:
193: editorPanel.add(ok);
194: editorPanel.add(cancel);
195: }
196:
197: /**
198: * Returns a reference to the editor component.
199: *
200: * @return the editor Component
201: */
202: public final SComponent getComponent() {
203: return editorComponent;
204: }
205:
206: public final SClickable getOKButton() {
207: return ok;
208: }
209:
210: public final SClickable getCancelButton() {
211: return cancel;
212: }
213:
214: /**
215: * Fast edit support is editing with reduced interaction. E.g. a boolean
216: * value can only have to states, true or false. So if editing is started,
217: * the editor just flips the state and fires editing stopped.
218: *
219: * @param b a <code>boolean</code> value
220: */
221: public final void setFastEdit(boolean b) {
222: fastEditSupport = b;
223: }
224:
225: /**
226: * Return if fast edit is activated.
227: *
228: * @return a <code>boolean</code> value
229: * @see #setFastEdit
230: */
231: public final boolean getFastEdit() {
232: return fastEditSupport;
233: }
234:
235: public Object getCellEditorValue() {
236: return delegate.getCellEditorValue();
237: }
238:
239: public boolean isCellEditable(EventObject anEvent) {
240: return delegate.isCellEditable(anEvent);
241: }
242:
243: public boolean shouldSelectCell(EventObject anEvent) {
244: return delegate.shouldSelectCell(anEvent);
245: }
246:
247: public boolean stopCellEditing() {
248: if (delegate.stopCellEditing()) {
249: fireEditingStopped();
250: return true;
251: }
252:
253: return false;
254: }
255:
256: public void cancelCellEditing() {
257: delegate.cancelCellEditing();
258: fireEditingCanceled();
259: }
260:
261: public void addCellEditorListener(CellEditorListener l) {
262: listenerList.add(CellEditorListener.class, l);
263: }
264:
265: public void removeCellEditorListener(CellEditorListener l) {
266: listenerList.remove(CellEditorListener.class, l);
267: }
268:
269: private ChangeEvent changeEvent = null;
270:
271: /*
272: * Notify all listeners that have registered interest for
273: * notification on this event type. The event instance
274: * is lazily created using the parameters passed into
275: * the fire method.
276: * @see EventListenerList
277: */
278: protected void fireEditingStopped() {
279: Object[] listeners = listenerList.getListenerList();
280: for (int i = listeners.length - 2; i >= 0; i -= 2) {
281: if (listeners[i] == CellEditorListener.class) {
282: if (changeEvent == null)
283: changeEvent = new ChangeEvent(this );
284: ((CellEditorListener) listeners[i + 1])
285: .editingStopped(changeEvent);
286: }
287: }
288: }
289:
290: /*
291: * Notify all listeners that have registered interest for
292: * notification on this event type. The event instance
293: * is lazily created using the parameters passed into
294: * the fire method.
295: * @see EventListenerList
296: */
297: protected void fireEditingCanceled() {
298: Object[] listeners = listenerList.getListenerList();
299: for (int i = listeners.length - 2; i >= 0; i -= 2) {
300: if (listeners[i] == CellEditorListener.class) {
301: if (changeEvent == null)
302: changeEvent = new ChangeEvent(this );
303: ((CellEditorListener) listeners[i + 1])
304: .editingCanceled(changeEvent);
305: }
306: }
307: }
308:
309: public SComponent getTreeCellEditorComponent(STree tree,
310: Object value, boolean isSelected, boolean expanded,
311: boolean leaf, int row) {
312:
313: delegate.setValue(value);
314: return editorPanel;
315: }
316:
317: public SComponent getTableCellEditorComponent(STable table,
318: Object value, boolean isSelected, int row, int column) {
319: delegate.setValue(value);
320:
321: return editorPanel;
322: }
323:
324: //
325: // Protected EditorDelegate class
326: //
327:
328: /**
329: * The interface all editing boils down to: setting the value for
330: * the editor and retrieve its value.
331: */
332: protected class EditorDelegate {
333: protected Object value;
334:
335: /**
336: * Retrieve the value from the component used as Editor.
337: * This method is called by the CellEditor to retrieve the
338: * value after editing.
339: *
340: * @return the value managed by the Editor.
341: */
342: public Object getCellEditorValue() {
343: return value;
344: }
345:
346: /**
347: * Set the Editors value. The task of this method is to
348: * pass the value to the editor component so that editing
349: * can be started.
350: *
351: * @param x the value to be edited.
352: */
353: public void setValue(Object x) {
354: this .value = x;
355: }
356:
357: public boolean isCellEditable(EventObject anEvent) {
358: return true;
359: }
360:
361: public boolean stopCellEditing() {
362: return true;
363: }
364:
365: public void cancelCellEditing() {
366: }
367:
368: public boolean shouldSelectCell(EventObject anEvent) {
369: return true;
370: }
371: }
372:
373: private final class FireEventListener implements ActionListener,
374: Serializable {
375: /**
376: *
377: */
378: private static final long serialVersionUID = 1L;
379:
380: public void actionPerformed(ActionEvent e) {
381: if (e.getSource() == ok) {
382: stopCellEditing();
383: } else if (e.getSource() == cancel) {
384: cancelCellEditing();
385: }
386: }
387: }
388:
389: private class EditorPanel extends SPanel implements
390: LowLevelEventListener {
391: boolean okFinalEvents;
392: boolean cancelFinalEvents;
393:
394: public EditorPanel() {
395: super (new SBoxLayout(SBoxLayout.HORIZONTAL));
396: }
397:
398: public void processLowLevelEvent(String name, String[] values) {
399: if (name.endsWith("_panel")) {
400: if ("ok".equals(values[0]))
401: okFinalEvents = true;
402: else if ("cancel".equals(values[0]))
403: cancelFinalEvents = true;
404: } else if (name.endsWith("_ed")
405: && editorComponent instanceof LowLevelEventListener) {
406: LowLevelEventListener lowLevelEventListener = (LowLevelEventListener) editorComponent;
407: lowLevelEventListener
408: .processLowLevelEvent(name, values);
409: }
410:
411: SForm.addArmedComponent(this );
412: }
413:
414: public void fireIntermediateEvents() {
415: if (okFinalEvents)
416: stopCellEditing();
417: if (cancelFinalEvents)
418: cancelCellEditing();
419: okFinalEvents = false;
420: cancelFinalEvents = false;
421: }
422:
423: public void fireFinalEvents() {
424: if (editorComponent instanceof LowLevelEventListener) {
425: LowLevelEventListener lowLevelEventListener = (LowLevelEventListener) editorComponent;
426: lowLevelEventListener.fireFinalEvents();
427: }
428: }
429:
430: public void setNameRaw(String uncheckedName) {
431: super .setNameRaw(uncheckedName + "_panel");
432: editorComponent.setNameRaw(uncheckedName + "_ed");
433: ok.setNameRaw(uncheckedName + "_ok");
434: cancel.setNameRaw(uncheckedName + "_cl");
435: }
436:
437: public boolean isEpochCheckEnabled() {
438: return true;
439: }
440: }
441: }
|