blob: 011ff992ab944c42f46e8257a7431390f574e2ed [file] [log] [blame]
/*******************************************************************************
* 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 image
*/
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 re-implement. If you re-implement this method, you should
* also re-implement <code>updateContents</code>.
* </p>
*
* @param cell
* the control for this cell editor
* @return control
*/
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 CellEditor
*/
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();
}
}