| /******************************************************************************* |
| * Copyright (c) 2006 Sybase, Inc. and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Sybase, Inc. - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.pagedesigner.properties.celleditors; |
| |
| import java.text.MessageFormat; |
| |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.CellEditor; |
| import org.eclipse.jface.viewers.ICellEditorListener; |
| import org.eclipse.jface.viewers.TextCellEditor; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.KeyAdapter; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Layout; |
| import org.eclipse.swt.widgets.Listener; |
| |
| /** |
| * CellEditorWrapper is a special cell editor, that wraps an existing cell |
| * editor by adding a small clickable button to end of it. |
| * |
| * Due to limitation of the CellEditor framework, this wrapping technology may |
| * resulting in some small inconvenience when change focus from the "wrapped" |
| * cell editor to the "added" button. |
| * |
| * This is an abstract class. Child class need override some methods. |
| * |
| * @author mengbo |
| */ |
| public abstract class CellEditorWrapper extends CellEditor { |
| /** |
| * The editor control. |
| */ |
| private Composite _editor; |
| |
| /** |
| * the wrapped cell editor |
| */ |
| private CellEditor _wrapped; |
| |
| /** |
| * The button. |
| */ |
| private Button _button; |
| |
| /** |
| * Internal class for laying out the dialog. |
| */ |
| private class DialogCellLayout extends Layout { |
| public void layout(Composite editor, boolean force) { |
| Rectangle bounds = editor.getClientArea(); |
| Point size = _button.computeSize(SWT.DEFAULT, SWT.DEFAULT, force); |
| // if (_wrapped != null) |
| _wrapped.getControl().setBounds(0, 0, bounds.width - size.x, |
| bounds.height); |
| _button.setBounds(bounds.width - size.x, 0, size.x, bounds.height); |
| } |
| |
| public Point computeSize(Composite editor, int wHint, int hHint, |
| boolean force) { |
| if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) |
| return new Point(wHint, hHint); |
| Point contentsSize = _wrapped.getControl().computeSize(SWT.DEFAULT, |
| SWT.DEFAULT, force); |
| Point buttonSize = _button.computeSize(SWT.DEFAULT, SWT.DEFAULT, |
| force); |
| // Just return the button width to ensure the button is not clipped |
| // if the label is long. |
| // The label will just use whatever extra width there is |
| Point result = new Point(buttonSize.x, Math.max(contentsSize.y, |
| buttonSize.y)); |
| return result; |
| } |
| } |
| |
| /** |
| * Default DialogCellEditor style |
| */ |
| private static final int defaultStyle = SWT.NONE; |
| |
| /** |
| * Creates a new dialog cell editor with no control |
| * |
| * @since 2.1 |
| */ |
| public CellEditorWrapper() { |
| setStyle(defaultStyle); |
| } |
| |
| /** |
| * Creates a new dialog cell editor parented under the given control. The |
| * cell editor value is <code>null</code> initially, and has no validator. |
| * |
| * @param parent |
| * the parent control |
| */ |
| protected CellEditorWrapper(Composite parent) { |
| this(parent, defaultStyle); |
| } |
| |
| /** |
| * Creates a new dialog cell editor parented under the given control. The |
| * cell editor value is <code>null</code> initially, and has no validator. |
| * |
| * @param parent |
| * the parent control |
| * @param style |
| * the style bits |
| * @since 2.1 |
| */ |
| protected CellEditorWrapper(Composite parent, int style) { |
| super(parent, style); |
| } |
| |
| /** |
| * Creates the button for this cell editor under the given parent control. |
| * <p> |
| * The default implementation of this framework method creates the button |
| * display on the right hand side of the dialog cell editor. Subclasses may |
| * extend or reimplement. |
| * </p> |
| * |
| * @param parent |
| * the parent control |
| * @return the new button control |
| */ |
| protected Button createButton(Composite parent) { |
| Button result = new Button(parent, SWT.DOWN); |
| result.setImage(getBindingImage()); |
| // result.setText("..."); //$NON-NLS-1$ |
| return result; |
| } |
| |
| /** |
| * Since createButton is called from constructor, so we could only let child |
| * class override this method to provide image. Rather than setting as |
| * property. |
| * |
| * @return |
| */ |
| protected abstract Image getBindingImage(); |
| |
| /** |
| * Creates the controls used to show the value of this cell editor. |
| * <p> |
| * The default implementation of this framework method creates a label |
| * widget, using the same font and background color as the parent control. |
| * </p> |
| * <p> |
| * Subclasses may reimplement. If you reimplement this method, you should |
| * also reimplement <code>updateContents</code>. |
| * </p> |
| * |
| * @param cell |
| * the control for this cell editor |
| */ |
| protected Control createContents(Composite cell) { |
| _wrapped = createWrappedCellEditor(cell); |
| if (_wrapped == null) { |
| _wrapped = new TextCellEditor(cell); |
| } |
| _wrapped.addListener(new ICellEditorListener() { |
| public void applyEditorValue() { |
| fireApplyEditorValue(); |
| } |
| |
| public void cancelEditor() { |
| fireCancelEditor(); |
| } |
| |
| public void editorValueChanged(boolean oldValidState, |
| boolean newValidState) { |
| fireEditorValueChanged(oldValidState, newValidState); |
| } |
| }); |
| _wrapped.addPropertyChangeListener(new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| // FIXME: |
| } |
| }); |
| |
| _wrapped.getControl().setVisible(true); |
| _wrapped.getControl().addListener(SWT.Hide, new Listener() { |
| public void handleEvent(Event event) { |
| Display.getCurrent().asyncExec(new Runnable() { |
| public void run() { |
| if (_wrapped != null && _wrapped.getControl() != null |
| && !_wrapped.getControl().isDisposed()) { |
| _wrapped.getControl().setVisible(true); |
| } else { |
| deactivate(); |
| } |
| } |
| }); |
| |
| } |
| }); |
| return _wrapped.getControl(); |
| } |
| |
| /** |
| * @param cell |
| * @return |
| */ |
| protected abstract CellEditor createWrappedCellEditor(Composite cell); |
| |
| /* |
| * (non-Javadoc) Method declared on CellEditor. |
| */ |
| protected Control createControl(Composite parent) { |
| Font font = parent.getFont(); |
| Color bg = parent.getBackground(); |
| |
| _editor = new Composite(parent, getStyle()); |
| _editor.setFont(font); |
| _editor.setBackground(bg); |
| _editor.setLayout(new DialogCellLayout()); |
| |
| createContents(_editor); |
| // updateContents(value); |
| |
| _button = createButton(_editor); |
| _button.setFont(font); |
| |
| _button.addKeyListener(new KeyAdapter() { |
| public void keyReleased(KeyEvent e) { |
| if (e.character == '\u001b') { // Escape |
| fireCancelEditor(); |
| } |
| } |
| }); |
| |
| _button.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| Object newValue = openDialogBox(_editor); |
| if (newValue != null) { |
| boolean newValidState = isCorrect(newValue); |
| if (newValidState) { |
| markDirty(); |
| doSetValue(newValue); |
| } else { |
| // try to insert the current value into the error |
| // message. |
| setErrorMessage(MessageFormat.format(getErrorMessage(), |
| new Object[] { newValue.toString() })); |
| } |
| fireApplyEditorValue(); |
| } |
| } |
| }); |
| |
| setValueValid(true); |
| |
| return _editor; |
| } |
| |
| /* |
| * (non-Javadoc) Method declared on CellEditor. The focus is set to the cell |
| * editor's button. |
| */ |
| protected void doSetFocus() { |
| if (_wrapped != null && _wrapped.getControl() != null |
| && !_wrapped.getControl().isDisposed()) { |
| _wrapped.setFocus(); |
| } else { |
| _button.setFocus(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) Method declared on CellEditor. |
| */ |
| protected Object doGetValue() { |
| return _wrapped.getValue(); |
| } |
| |
| /* |
| * (non-Javadoc) Method declared on CellEditor. |
| */ |
| protected void doSetValue(Object value) { |
| if (_wrapped != null) { |
| _wrapped.setValue(value); |
| } |
| } |
| |
| /** |
| * Opens a dialog box under the given parent control and returns the |
| * dialog's value when it closes, or <code>null</code> if the dialog was |
| * cancelled or no selection was made in the dialog. |
| * <p> |
| * This framework method must be implemented by concrete subclasses. It is |
| * called when the user has pressed the button and the dialog box must pop |
| * up. |
| * </p> |
| * |
| * @param cellEditorWindow |
| * the parent control cell editor's window so that a subclass can |
| * adjust the dialog box accordingly |
| * @return the selected value, or <code>null</code> if the dialog was |
| * cancelled or no selection was made in the dialog |
| */ |
| protected abstract Object openDialogBox(Control cellEditorWindow); |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.CellEditor#activate() |
| */ |
| public void activate() { |
| super.activate(); |
| _wrapped.activate(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.CellEditor#deactivate() |
| */ |
| public void deactivate() { |
| super.deactivate(); |
| // if (_wrapped != null) |
| // { |
| // _wrapped.deactivate(); |
| // } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.CellEditor#dispose() |
| */ |
| public void dispose() { |
| _wrapped.dispose(); |
| super.dispose(); |
| } |
| |
| } |